diff --git a/contrib/uwsgi-sogs-standalone.ini b/contrib/uwsgi-sogs-standalone.ini index 16a7f977..83c07141 100644 --- a/contrib/uwsgi-sogs-standalone.ini +++ b/contrib/uwsgi-sogs-standalone.ini @@ -25,7 +25,7 @@ gid = GROUP plugins = python3,http processes = 2 enable-threads = true -http = :80 +http-socket = [::]:80 mount = /=sogs.web:app mule = sogs.mule:run log-4xx = true diff --git a/sogs/model/room.py b/sogs/model/room.py index 7217b116..ed8540dd 100644 --- a/sogs/model/room.py +++ b/sogs/model/room.py @@ -1243,6 +1243,49 @@ def delete_all_posts(self, poster: User, *, deleter: User): return len(deleted), files_removed + def delete_all_user_reactions(self, poster: User, *, deleter: User): + """ + Delete all emoji reactions placed on messages in the room by `poster`. + `deleter` must be a moderator if not deleting his/her own reactions, and + must be an `admin` if trying to delete all of the posts of another admin. + """ + + fail = None + if poster.id != deleter.id and not self.check_moderator(deleter): + fail = "user is not a moderator" + elif self.check_admin(poster) and not self.check_admin(deleter): + fail = "only admins can delete all reactions of another admin" + + if fail is not None: + app.logger.warning( + f"Error deleting all reactions by {poster} from {self} by {deleter}: {fail}" + ) + raise BadPermission() + + with db.transaction(): + deleted = [ + r[0] + for r in query( + 'SELECT reaction FROM user_reactions WHERE "user" = :u AND reaction IN (SELECT id FROM reactions WHERE message IN (SELECT id FROM messages WHERE room = :r))', + r=self.id, + u=poster.id, + ) + ] + + query( + 'DELETE FROM user_reactions WHERE "user" = :u AND reaction IN (SELECT id FROM reactions WHERE message IN (SELECT id FROM messages WHERE room = :r))', + r=self.id, + u=poster.id, + ) + + # FIXME: send `deleted` to mule + + app.logger.debug( + f"Delete all reactions by {poster} from {self}: {len(deleted)} reactions" + ) + + return len(deleted) + def attachments_size(self): """Returns the number and aggregate size of attachments currently stored in this room""" return query( diff --git a/sogs/routes/rooms.py b/sogs/routes/rooms.py index 4487a71b..fbefcb68 100644 --- a/sogs/routes/rooms.py +++ b/sogs/routes/rooms.py @@ -990,3 +990,58 @@ def delete_user_posts_from_all_rooms(sid): pass return jsonify({"total": total, "rooms": deletions}) + + +@rooms.delete("/room//all/reactions/") +def delete_all_reactions(room, sid): + """ + Deletes all emoji reactions placed by a user in a room + + # URL Parameters + + - `sid` — the session id of the user whose reactions are to be deleted + + # Return value + + An empty json object is returned. + + # Error status codes + + - 403 Forbidden — if the invoking user does not have access to the room. + - 404 Not Found — if the user we are deleting posts from made no posts in this room. + """ + user = muser.User(session_id=sid, autovivify=False) + deleted = room.delete_all_user_reactions(user, deleter=g.user) + if not deleted: + abort(http.NOT_FOUND) + return jsonify({}) + + +@rooms.delete("/rooms/all/reactions/") +def delete_user_reactions_from_all_rooms(sid): + """ + Deletes all emoji reactions by a given user from all rooms. + + # URL Parameters + + - `sid` — the session id of the user whose reactions are to be deleted + + # Return value + + A JSON dict with the keys: + + - `total` — The total number of reactions deleted across all rooms. + - `messages` — A dict of room tokens and their deletion counts. + """ + deletions = {} + total = 0 + user = muser.User(session_id=sid, autovivify=False) + for room in mroom.get_accessible_rooms(g.user): + try: + count = room.delete_all_user_reactions(user, deleter=g.user) + total += count + deletions[room.token] = count + except exc.BadPermission: + pass + + return jsonify({"total": total, "messages": deletions})