diff --git a/db/migrations/8_account_comments.sql b/db/migrations/8_account_comments.sql new file mode 100644 index 0000000..a4b0b4a --- /dev/null +++ b/db/migrations/8_account_comments.sql @@ -0,0 +1,13 @@ +-- +migrate up +CREATE TABLE account_comments ( + id SERIAL PRIMARY KEY, + + account_id INTEGER NOT NULL references users(id), + comment TEXT NOT NULL, + + created_at TEXT NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'now')), + likes INTEGER NOT NULL DEFAULT 0 +); + +-- +migrate down +DROP TABLE account_comments; \ No newline at end of file diff --git a/src/endpoints/misc/likeItem.cr b/src/endpoints/misc/likeItem.cr index 138ee41..1659b17 100644 --- a/src/endpoints/misc/likeItem.cr +++ b/src/endpoints/misc/likeItem.cr @@ -18,16 +18,19 @@ CrystalGauntlet.endpoints["/likeGJItem211.php"] = ->(body : String): String { table = "" column = "" case type - when 1 + when 1 # level like table = "levels" column = "id" - else # type 2 = comment, type 3 = account comments + when 2 # level comment like + table = "account_comments" + column = "id" + when 3 # account comments return "-1" end is_like = (params["isLike"]? || "1").to_i sign = is_like == 1 ? '+' : '-' - + # note: formatting them like this is not a security vulnerability as the only possibilities for table, sign # and column are already known and not controlled directly by user input DATABASE.exec "update #{table} set likes = likes #{sign} 1 where #{column} = ?", item_id diff --git a/src/endpoints/users/addProfileComment.cr b/src/endpoints/users/addProfileComment.cr new file mode 100644 index 0000000..2c6ec13 --- /dev/null +++ b/src/endpoints/users/addProfileComment.cr @@ -0,0 +1,25 @@ +require "uri" + +include CrystalGauntlet + +CrystalGauntlet.endpoints["/uploadGJAccComment20.php"] = ->(body : String): String { + params = URI::Params.parse(body) + puts params.inspect + + user_id, account_id = Accounts.auth(params) + if !(user_id && account_id) + return "-1" + end + + comment = params["comment"]? + + if comment && comment != "" + # todo: cap comment size + comment_value = Base64.decode_string comment # usual b64, surprisingly + next_id = (DATABASE.scalar("select max(id) from account_comments").as(Int64 | Nil) || 0) + 1 + DATABASE.exec("insert into account_comments (id, account_id, comment) values (?, ?, ?)", next_id, account_id, comment_value) + return "1" + else + return "-1" + end +} diff --git a/src/endpoints/users/deleteProfileComment.cr b/src/endpoints/users/deleteProfileComment.cr new file mode 100644 index 0000000..b3d2a90 --- /dev/null +++ b/src/endpoints/users/deleteProfileComment.cr @@ -0,0 +1,26 @@ +require "uri" + +include CrystalGauntlet + +CrystalGauntlet.endpoints["/deleteGJAccComment20.php"] = ->(body : String): String { + params = URI::Params.parse(body) + puts params.inspect + + user_id, account_id = Accounts.auth(params) + if !(user_id && account_id) + return "-1" + end + + comment_id = params["commentID"].to_i + + # kind of a dumb hack, but it works + target_account_id = DATABASE.scalar("select max(account_id) from account_comments where id = ?", comment_id).as(Int64 | Nil) + + # todo: let mods delete any comment + if target_account_id && account_id == target_account_id + DATABASE.exec("delete from account_comments where id = ?", comment_id) + return "1" + else + return "-1" + end +} diff --git a/src/endpoints/users/getProfileComments.cr b/src/endpoints/users/getProfileComments.cr new file mode 100644 index 0000000..ad4bd18 --- /dev/null +++ b/src/endpoints/users/getProfileComments.cr @@ -0,0 +1,41 @@ +require "uri" + +include CrystalGauntlet + +comments_per_page = 10 + +CrystalGauntlet.endpoints["/getGJAccountComments20.php"] = ->(body : String): String { + params = URI::Params.parse(body) + puts params.inspect + + account_id = params["accountID"].to_i + + comment_offset = (params["page"]? || "0").to_i * comments_per_page + + amount = DATABASE.scalar("select count(*) from account_comments where account_id = ?", account_id) + + users_str = [] of String + + DATABASE.query("select id, comment, created_at, likes from account_comments where account_id = ? order by created_at desc limit #{comments_per_page} offset #{comment_offset}", account_id) do |rs| + rs.each do + id = rs.read(Int32) + comment = rs.read(String) + created_at = rs.read(String) + likes = rs.read(Int32) + + users_str << Format.fmt_comment({ + 2 => Base64.encode(comment).strip("\n"), + 3 => account_id, + 4 => likes, + 5 => 0, + 7 => likes < -3, # todo: config? + #9 => Format.fmt_timespan(Time.utc - Time.parse(created_at, Format::TIME_FORMAT, Time::Location::UTC)), + 6 => id + }) + end + end + + search_meta = "#{amount}:#{comment_offset}:#{comments_per_page}" + + [users_str.join("|"), search_meta].join("#") +} diff --git a/src/lib/format.cr b/src/lib/format.cr index 64e9f20..e5b4d16 100644 --- a/src/lib/format.cr +++ b/src/lib/format.cr @@ -46,6 +46,10 @@ module CrystalGauntlet::Format def fmt_song(hash) : String hash.map_with_index{ |(i, v)| "#{i}~|~#{fmt_value(v)}" }.join("~|~") end + + def fmt_comment(hash) : String + hash.map_with_index{ |(i, v)| "#{i}~#{fmt_value(v)}" }.join("~") + end end module CrystalGauntlet::GDBase64