From 7691f5352025d7b2158ebae73417dd8619baea32 Mon Sep 17 00:00:00 2001 From: Samantaz Fox Date: Fri, 3 Dec 2021 03:29:52 +0100 Subject: [PATCH] Move DB queries related to 'users' in a separate module (2/2) --- src/invidious.cr | 18 ++-- src/invidious/channels/channels.cr | 7 +- src/invidious/database/users.cr | 89 ++++++++++++++++++++ src/invidious/routes/api/v1/authenticated.cr | 5 +- src/invidious/routes/embed.cr | 2 +- src/invidious/routes/feeds.cr | 7 +- src/invidious/routes/login.cr | 8 +- src/invidious/routes/preferences.cr | 20 ++--- src/invidious/routes/watch.cr | 2 +- src/invidious/users.cr | 6 +- 10 files changed, 121 insertions(+), 43 deletions(-) diff --git a/src/invidious.cr b/src/invidious.cr index 91f19d69..0149be11 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -759,18 +759,18 @@ post "/data_control" do |env| user.subscriptions = get_batch_channels(user.subscriptions, PG_DB, false, false) - PG_DB.exec("UPDATE users SET feed_needs_update = true, subscriptions = $1 WHERE email = $2", user.subscriptions, user.email) + Invidious::Database::Users.update_subscriptions(user) end if body["watch_history"]? user.watched += body["watch_history"].as_a.map(&.as_s) user.watched.uniq! - PG_DB.exec("UPDATE users SET watched = $1 WHERE email = $2", user.watched, user.email) + Invidious::Database::Users.update_watch_history(user) end if body["preferences"]? user.preferences = Preferences.from_json(body["preferences"].to_json) - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", user.preferences.to_json, user.email) + Invidious::Database::Users.update_preferences(user) end if playlists = body["playlists"]?.try &.as_a? @@ -831,7 +831,7 @@ post "/data_control" do |env| user.subscriptions = get_batch_channels(user.subscriptions, PG_DB, false, false) - PG_DB.exec("UPDATE users SET feed_needs_update = true, subscriptions = $1 WHERE email = $2", user.subscriptions, user.email) + Invidious::Database::Users.update_subscriptions(user) when "import_freetube" user.subscriptions += body.scan(/"channelId":"(?[a-zA-Z0-9_-]{24})"/).map do |md| md["channel_id"] @@ -840,7 +840,7 @@ post "/data_control" do |env| user.subscriptions = get_batch_channels(user.subscriptions, PG_DB, false, false) - PG_DB.exec("UPDATE users SET feed_needs_update = true, subscriptions = $1 WHERE email = $2", user.subscriptions, user.email) + Invidious::Database::Users.update_subscriptions(user) when "import_newpipe_subscriptions" body = JSON.parse(body) user.subscriptions += body["subscriptions"].as_a.compact_map do |channel| @@ -859,7 +859,7 @@ post "/data_control" do |env| user.subscriptions = get_batch_channels(user.subscriptions, PG_DB, false, false) - PG_DB.exec("UPDATE users SET feed_needs_update = true, subscriptions = $1 WHERE email = $2", user.subscriptions, user.email) + Invidious::Database::Users.update_subscriptions(user) when "import_newpipe" Compress::Zip::Reader.open(IO::Memory.new(body)) do |file| file.each_entry do |entry| @@ -871,14 +871,14 @@ post "/data_control" do |env| user.watched += db.query_all("SELECT url FROM streams", as: String).map(&.lchop("https://www.youtube.com/watch?v=")) user.watched.uniq! - PG_DB.exec("UPDATE users SET watched = $1 WHERE email = $2", user.watched, user.email) + Invidious::Database::Users.update_watch_history(user) user.subscriptions += db.query_all("SELECT url FROM subscriptions", as: String).map(&.lchop("https://www.youtube.com/channel/")) user.subscriptions.uniq! user.subscriptions = get_batch_channels(user.subscriptions, PG_DB, false, false) - PG_DB.exec("UPDATE users SET feed_needs_update = true, subscriptions = $1 WHERE email = $2", user.subscriptions, user.email) + Invidious::Database::Users.update_subscriptions(user) db.close tempfile.delete @@ -962,7 +962,7 @@ post "/change_password" do |env| end new_password = Crypto::Bcrypt::Password.create(new_password, cost: 10) - PG_DB.exec("UPDATE users SET password = $1 WHERE email = $2", new_password.to_s, user.email) + Invidious::Database::Users.update_password(user, new_password.to_s) env.redirect referer end diff --git a/src/invidious/channels/channels.cr b/src/invidious/channels/channels.cr index 5d962ab4..2ec510f0 100644 --- a/src/invidious/channels/channels.cr +++ b/src/invidious/channels/channels.cr @@ -238,8 +238,7 @@ def fetch_channel(ucid, db, pull_all_videos = true, locale = nil) if was_insert LOGGER.trace("fetch_channel: #{ucid} : video #{video_id} : Inserted, updating subscriptions") - db.exec("UPDATE users SET notifications = array_append(notifications, $1), \ - feed_needs_update = true WHERE $2 = ANY(subscriptions)", video.id, video.ucid) + Invidious::Database::Users.add_notification(video) else LOGGER.trace("fetch_channel: #{ucid} : video #{video_id} : Updated") end @@ -275,9 +274,7 @@ def fetch_channel(ucid, db, pull_all_videos = true, locale = nil) # so since they don't provide a published date here we can safely ignore them. if Time.utc - video.published > 1.minute was_insert = Invidious::Database::ChannelVideos.insert(video) - - db.exec("UPDATE users SET notifications = array_append(notifications, $1), \ - feed_needs_update = true WHERE $2 = ANY(subscriptions)", video.id, video.ucid) if was_insert + Invidious::Database::Users.add_notification(video) if was_insert end end diff --git a/src/invidious/database/users.cr b/src/invidious/database/users.cr index aa3b9f85..71650918 100644 --- a/src/invidious/database/users.cr +++ b/src/invidious/database/users.cr @@ -39,6 +39,16 @@ module Invidious::Database::Users # Update (history) # ------------------- + def update_watch_history(user : User) + request = <<-SQL + UPDATE users + SET watched = $1 + WHERE email = $2 + SQL + + PG_DB.exec(request, user.watched, user.email) + end + def mark_watched(user : User, vid : String) request = <<-SQL UPDATE users @@ -73,6 +83,16 @@ module Invidious::Database::Users # Update (channels) # ------------------- + def update_subscriptions(user : User) + request = <<-SQL + UPDATE users + SET feed_needs_update = true, subscriptions = $1 + WHERE email = $2 + SQL + + PG_DB.exec(request, user.subscriptions, user.email) + end + def subscribe_channel(user : User, ucid : String) request = <<-SQL UPDATE users @@ -95,6 +115,65 @@ module Invidious::Database::Users PG_DB.exec(request, ucid, user.email) end + # ------------------- + # Update (notifs) + # ------------------- + + def add_notification(video : ChannelVideo) + request = <<-SQL + UPDATE users + SET notifications = array_append(notifications, $1), + feed_needs_update = true + WHERE $2 = ANY(subscriptions) + SQL + + PG_DB.exec(request, video.id, video.ucid) + end + + def remove_notification(user : User, vid : String) + request = <<-SQL + UPDATE users + SET notifications = array_remove(notifications, $1) + WHERE email = $2 + SQL + + PG_DB.exec(request, vid, user.email) + end + + def clear_notifications(user : User) + request = <<-SQL + UPDATE users + SET notifications = $1, updated = $2 + WHERE email = $3 + SQL + + PG_DB.exec(request, [] of String, Time.utc, user) + end + + # ------------------- + # Update (misc) + # ------------------- + + def update_preferences(user : User) + request = <<-SQL + UPDATE users + SET preferences = $1 + WHERE email = $2 + SQL + + PG_DB.exec(request, user.preferences.to_json, user.email) + end + + def update_password(user : User, pass : String) + request = <<-SQL + UPDATE users + SET password = $1 + WHERE email = $2 + SQL + + PG_DB.exec(request, user.email, pass) + end + # ------------------- # Select # ------------------- @@ -126,4 +205,14 @@ module Invidious::Database::Users return PG_DB.query_one?(request, token, as: User) end + + def select_notifications(user : User) : Array(String) + request = <<-SQL + SELECT notifications + FROM users + WHERE email = $1 + SQL + + return PG_DB.query_one(request, user.email, as: Array(String)) + end end diff --git a/src/invidious/routes/api/v1/authenticated.cr b/src/invidious/routes/api/v1/authenticated.cr index d9b58ebf..62b09f79 100644 --- a/src/invidious/routes/api/v1/authenticated.cr +++ b/src/invidious/routes/api/v1/authenticated.cr @@ -22,12 +22,11 @@ module Invidious::Routes::API::V1::Authenticated user = env.get("user").as(User) begin - preferences = Preferences.from_json(env.request.body || "{}") + user.preferences = Preferences.from_json(env.request.body || "{}") rescue - preferences = user.preferences end - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email) + Invidious::Database::Users.update_preferences(user) env.response.status_code = 204 end diff --git a/src/invidious/routes/embed.cr b/src/invidious/routes/embed.cr index 049ee344..2c648b5a 100644 --- a/src/invidious/routes/embed.cr +++ b/src/invidious/routes/embed.cr @@ -137,7 +137,7 @@ module Invidious::Routes::Embed # end if notifications && notifications.includes? id - PG_DB.exec("UPDATE users SET notifications = array_remove(notifications, $1) WHERE email = $2", id, user.as(User).email) + Invidious::Database::Users.remove_notification(user.as(User), id) env.get("user").as(User).notifications.delete(id) notifications.delete(id) end diff --git a/src/invidious/routes/feeds.cr b/src/invidious/routes/feeds.cr index 4e7ec9ad..be58dd8d 100644 --- a/src/invidious/routes/feeds.cr +++ b/src/invidious/routes/feeds.cr @@ -99,8 +99,7 @@ module Invidious::Routes::Feeds # we know a user has looked at their feed e.g. in the past 10 minutes, # they've already seen a video posted 20 minutes ago, and don't need # to be notified. - PG_DB.exec("UPDATE users SET notifications = $1, updated = $2 WHERE email = $3", [] of String, Time.utc, - user.email) + Invidious::Database::Users.clear_notifications(user) user.notifications = [] of String env.set "user", user @@ -417,9 +416,7 @@ module Invidious::Routes::Feeds }) was_insert = Invidious::Database::ChannelVideos.insert(video, with_premiere_timestamp: true) - - PG_DB.exec("UPDATE users SET notifications = array_append(notifications, $1), - feed_needs_update = true WHERE $2 = ANY(subscriptions)", video.id, video.ucid) if was_insert + Invidious::Database::Users.add_notification(video) if was_insert end end diff --git a/src/invidious/routes/login.cr b/src/invidious/routes/login.cr index 8f703464..c94fd09b 100644 --- a/src/invidious/routes/login.cr +++ b/src/invidious/routes/login.cr @@ -303,8 +303,8 @@ module Invidious::Routes::Login end if env.request.cookies["PREFS"]? - preferences = env.get("preferences").as(Preferences) - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email) + user.preferences = env.get("preferences").as(Preferences) + Invidious::Database::Users.update_preferences(user) cookie = env.request.cookies["PREFS"] cookie.expires = Time.utc(1990, 1, 1) @@ -470,8 +470,8 @@ module Invidious::Routes::Login end if env.request.cookies["PREFS"]? - preferences = env.get("preferences").as(Preferences) - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email) + user.preferences = env.get("preferences").as(Preferences) + Invidious::Database::Users.update_preferences(user) cookie = env.request.cookies["PREFS"] cookie.expires = Time.utc(1990, 1, 1) diff --git a/src/invidious/routes/preferences.cr b/src/invidious/routes/preferences.cr index 15c00700..a832076c 100644 --- a/src/invidious/routes/preferences.cr +++ b/src/invidious/routes/preferences.cr @@ -170,11 +170,12 @@ module Invidious::Routes::PreferencesRoute vr_mode: vr_mode, show_nick: show_nick, save_player_pos: save_player_pos, - }.to_json).to_json + }.to_json) if user = env.get? "user" user = user.as(User) - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences, user.email) + user.preferences = preferences + Invidious::Database::Users.update_preferences(user) if CONFIG.admins.includes? user.email CONFIG.default_user_preferences.default_home = env.params.body["admin_default_home"]?.try &.as(String) || CONFIG.default_user_preferences.default_home @@ -220,10 +221,10 @@ module Invidious::Routes::PreferencesRoute end if CONFIG.domain - env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{CONFIG.domain}", value: URI.encode_www_form(preferences), expires: Time.utc + 2.years, + env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", domain: "#{CONFIG.domain}", value: URI.encode_www_form(preferences.to_json), expires: Time.utc + 2.years, secure: secure, http_only: true) else - env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", value: URI.encode_www_form(preferences), expires: Time.utc + 2.years, + env.response.cookies["PREFS"] = HTTP::Cookie.new(name: "PREFS", value: URI.encode_www_form(preferences.to_json), expires: Time.utc + 2.years, secure: secure, http_only: true) end end @@ -241,18 +242,15 @@ module Invidious::Routes::PreferencesRoute if user = env.get? "user" user = user.as(User) - preferences = user.preferences - case preferences.dark_mode + case user.preferences.dark_mode when "dark" - preferences.dark_mode = "light" + user.preferences.dark_mode = "light" else - preferences.dark_mode = "dark" + user.preferences.dark_mode = "dark" end - preferences = preferences.to_json - - PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences, user.email) + Invidious::Database::Users.update_preferences(user) else preferences = env.get("preferences").as(Preferences) diff --git a/src/invidious/routes/watch.cr b/src/invidious/routes/watch.cr index c1ec0bc6..f7bd7d81 100644 --- a/src/invidious/routes/watch.cr +++ b/src/invidious/routes/watch.cr @@ -80,7 +80,7 @@ module Invidious::Routes::Watch end if notifications && notifications.includes? id - PG_DB.exec("UPDATE users SET notifications = array_remove(notifications, $1) WHERE email = $2", id, user.as(User).email) + Invidious::Database::Users.remove_notification(user.as(User), id) env.get("user").as(User).notifications.delete(id) notifications.delete(id) end diff --git a/src/invidious/users.cr b/src/invidious/users.cr index 933c451d..efc4dd52 100644 --- a/src/invidious/users.cr +++ b/src/invidious/users.cr @@ -224,8 +224,7 @@ def get_subscription_feed(db, user, max_results = 40, page = 1) limit = max_results.clamp(0, MAX_ITEMS_PER_PAGE) offset = (page - 1) * limit - notifications = db.query_one("SELECT notifications FROM users WHERE email = $1", user.email, - as: Array(String)) + notifications = Invidious::Database::Users.select_notifications(user) view_name = "subscriptions_#{sha256(user.email)}" if user.preferences.notifications_only && !notifications.empty? @@ -296,8 +295,7 @@ def get_subscription_feed(db, user, max_results = 40, page = 1) else nil # Ignore end - notifications = PG_DB.query_one("SELECT notifications FROM users WHERE email = $1", user.email, as: Array(String)) - + notifications = Invidious::Database::Users.select_notifications(user) notifications = videos.select { |v| notifications.includes? v.id } videos = videos - notifications end