Update routes.py
This commit is contained in:
parent
49494e5399
commit
98997e26ca
366
routes.py
366
routes.py
@ -7,9 +7,13 @@ import time
|
|||||||
from flask import jsonify, request
|
from flask import jsonify, request
|
||||||
|
|
||||||
from features import (
|
from features import (
|
||||||
|
DM_LAYOUT_MODES,
|
||||||
|
LAST_ACTIVE_VISIBILITIES,
|
||||||
PAGE_TYPES,
|
PAGE_TYPES,
|
||||||
PAGE_VISIBILITIES,
|
PAGE_VISIBILITIES,
|
||||||
|
PRESENCE_MODES,
|
||||||
PROFILE_BIO_MODES,
|
PROFILE_BIO_MODES,
|
||||||
|
PROFILE_VISIBILITIES,
|
||||||
REACTION_EMOJI_RE,
|
REACTION_EMOJI_RE,
|
||||||
TEAM_MEMBER_ROLES,
|
TEAM_MEMBER_ROLES,
|
||||||
THEME_MODES,
|
THEME_MODES,
|
||||||
@ -135,6 +139,9 @@ def register_routes(app, ctx):
|
|||||||
user["id"] if user else None,
|
user["id"] if user else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def build_local_stub_share_url(kind: str, object_id: int) -> str:
|
||||||
|
return f"/shared/{kind}/{object_id}"
|
||||||
|
|
||||||
def build_room_helper_call_id(room) -> str:
|
def build_room_helper_call_id(room) -> str:
|
||||||
return f"room-{room['slug']}"
|
return f"room-{room['slug']}"
|
||||||
|
|
||||||
@ -1973,6 +1980,86 @@ def register_routes(app, ctx):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@app.route("/api/messages/<int:message_id>/bookmark", methods=["POST"])
|
||||||
|
def api_bookmark_message(message_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"status": "stubbed", "message_id": message_id})
|
||||||
|
|
||||||
|
@app.route("/api/messages/<int:message_id>/bookmark", methods=["DELETE"])
|
||||||
|
def api_unbookmark_message(message_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"status": "stubbed", "message_id": message_id})
|
||||||
|
|
||||||
|
@app.route("/api/bookmarks")
|
||||||
|
def api_list_bookmarks():
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"messages": []})
|
||||||
|
|
||||||
|
@app.route("/api/messages/<int:message_id>/pin", methods=["POST"])
|
||||||
|
def api_pin_message(message_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"status": "stubbed", "message_id": message_id})
|
||||||
|
|
||||||
|
@app.route("/api/messages/<int:message_id>/pin", methods=["DELETE"])
|
||||||
|
def api_unpin_message(message_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"status": "stubbed", "message_id": message_id})
|
||||||
|
|
||||||
|
@app.route("/api/pins")
|
||||||
|
def api_list_pins():
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"messages": []})
|
||||||
|
|
||||||
|
@app.route("/api/messages/<int:message_id>/share", methods=["POST"])
|
||||||
|
def api_share_message(message_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"share": {
|
||||||
|
"url": build_local_stub_share_url("message", message_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/api/attachments/<int:attachment_id>/share", methods=["POST"])
|
||||||
|
def api_share_attachment(attachment_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"share": {
|
||||||
|
"url": build_local_stub_share_url("attachment", attachment_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@app.route("/api/presence", methods=["POST"])
|
@app.route("/api/presence", methods=["POST"])
|
||||||
def api_presence_ping():
|
def api_presence_ping():
|
||||||
if not csrf_valid():
|
if not csrf_valid():
|
||||||
@ -4021,6 +4108,138 @@ def register_routes(app, ctx):
|
|||||||
audit("page_deleted", user["id"], "page", str(page["id"]), f"{team_slug}/{page_slug}")
|
audit("page_deleted", user["id"], "page", str(page["id"]), f"{team_slug}/{page_slug}")
|
||||||
return jsonify({"status": "deleted"})
|
return jsonify({"status": "deleted"})
|
||||||
|
|
||||||
|
@app.route("/api/teams/<string:team_slug>/pages/<string:page_slug>/versions")
|
||||||
|
def api_list_page_versions(team_slug: str, page_slug: str):
|
||||||
|
user = current_user()
|
||||||
|
|
||||||
|
with get_db() as db:
|
||||||
|
page = db.execute(
|
||||||
|
f"""
|
||||||
|
{team_page_select()}
|
||||||
|
WHERE t.slug = ?
|
||||||
|
AND p.slug = ?
|
||||||
|
AND p.is_active = 1
|
||||||
|
AND t.is_active = 1
|
||||||
|
""",
|
||||||
|
(team_slug, page_slug),
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if not page:
|
||||||
|
return jsonify({"error": "Page not found."}), 404
|
||||||
|
|
||||||
|
permitted = bool(
|
||||||
|
page["visibility"] == "public"
|
||||||
|
or (user and (user["role"] in {"moderator", "admin"} or is_team_member(page["team_id"], user["id"])))
|
||||||
|
)
|
||||||
|
if not permitted:
|
||||||
|
if not user:
|
||||||
|
return jsonify({"error": "Login required.", "code": "login_required"}), 401
|
||||||
|
return jsonify({"error": "Forbidden.", "code": "forbidden"}), 403
|
||||||
|
|
||||||
|
return jsonify({"versions": []})
|
||||||
|
|
||||||
|
@app.route("/api/page-versions/<int:version_id>")
|
||||||
|
def api_get_page_version(version_id: int):
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"version": {
|
||||||
|
"id": version_id,
|
||||||
|
"version_number": 1,
|
||||||
|
"title": "version unavailable",
|
||||||
|
"body_html": "<p>page version history is not enabled on this server.</p>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/api/page-versions/<int:version_id>/restore", methods=["POST"])
|
||||||
|
def api_restore_page_version(version_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
return jsonify({"error": "Page version restore is not enabled on this server."}), 501
|
||||||
|
|
||||||
|
@app.route("/api/teams/<string:team_slug>/pages/<string:page_slug>/comments")
|
||||||
|
def api_list_page_comments(team_slug: str, page_slug: str):
|
||||||
|
user = current_user()
|
||||||
|
|
||||||
|
with get_db() as db:
|
||||||
|
page = db.execute(
|
||||||
|
f"""
|
||||||
|
{team_page_select()}
|
||||||
|
WHERE t.slug = ?
|
||||||
|
AND p.slug = ?
|
||||||
|
AND p.is_active = 1
|
||||||
|
AND t.is_active = 1
|
||||||
|
""",
|
||||||
|
(team_slug, page_slug),
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if not page:
|
||||||
|
return jsonify({"error": "Page not found."}), 404
|
||||||
|
|
||||||
|
permitted = bool(
|
||||||
|
page["visibility"] == "public"
|
||||||
|
or (user and (user["role"] in {"moderator", "admin"} or is_team_member(page["team_id"], user["id"])))
|
||||||
|
)
|
||||||
|
if not permitted:
|
||||||
|
if not user:
|
||||||
|
return jsonify({"error": "Login required.", "code": "login_required"}), 401
|
||||||
|
return jsonify({"error": "Forbidden.", "code": "forbidden"}), 403
|
||||||
|
|
||||||
|
return jsonify({"comments": []})
|
||||||
|
|
||||||
|
@app.route("/api/teams/<string:team_slug>/pages/<string:page_slug>/comments", methods=["POST"])
|
||||||
|
def api_create_page_comment(team_slug: str, page_slug: str):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_writable_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"error": "Page comments are not enabled on this server."}), 501
|
||||||
|
|
||||||
|
@app.route("/api/page-comments/<int:comment_id>", methods=["DELETE"])
|
||||||
|
def api_delete_page_comment(comment_id: int):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
user, error = require_writable_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
return jsonify({"error": "Page comments are not enabled on this server."}), 501
|
||||||
|
|
||||||
|
@app.route("/api/teams/<string:team_slug>/pages/<string:page_slug>/share", methods=["POST"])
|
||||||
|
def api_create_page_share(team_slug: str, page_slug: str):
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
|
||||||
|
user, error = require_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
with get_db() as db:
|
||||||
|
page = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT p.id
|
||||||
|
FROM pages AS p
|
||||||
|
JOIN teams AS t
|
||||||
|
ON t.id = p.team_id
|
||||||
|
WHERE t.slug = ?
|
||||||
|
AND p.slug = ?
|
||||||
|
AND p.is_active = 1
|
||||||
|
AND t.is_active = 1
|
||||||
|
""",
|
||||||
|
(team_slug, page_slug),
|
||||||
|
).fetchone()
|
||||||
|
|
||||||
|
if not page:
|
||||||
|
return jsonify({"error": "Page not found."}), 404
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"share": {
|
||||||
|
"url": build_local_stub_share_url("page", page["id"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
@app.route("/api/profile")
|
@app.route("/api/profile")
|
||||||
def api_get_my_profile():
|
def api_get_my_profile():
|
||||||
user, error = require_user()
|
user, error = require_user()
|
||||||
@ -4036,7 +4255,8 @@ def register_routes(app, ctx):
|
|||||||
role,
|
role,
|
||||||
status,
|
status,
|
||||||
restricted_until,
|
restricted_until,
|
||||||
created_at
|
created_at,
|
||||||
|
last_login_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
""",
|
""",
|
||||||
@ -4070,7 +4290,9 @@ def register_routes(app, ctx):
|
|||||||
profile_background_color,
|
profile_background_color,
|
||||||
profile_banner_color,
|
profile_banner_color,
|
||||||
profile_visibility,
|
profile_visibility,
|
||||||
last_active_visibility
|
last_active_visibility,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge
|
||||||
FROM user_settings
|
FROM user_settings
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
""",
|
""",
|
||||||
@ -4081,7 +4303,6 @@ def register_routes(app, ctx):
|
|||||||
|
|
||||||
@app.route("/api/profile", methods=["PATCH"])
|
@app.route("/api/profile", methods=["PATCH"])
|
||||||
def api_update_my_profile():
|
def api_update_my_profile():
|
||||||
|
|
||||||
if not csrf_valid():
|
if not csrf_valid():
|
||||||
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
|
||||||
@ -4104,6 +4325,16 @@ def register_routes(app, ctx):
|
|||||||
bio_mode = str(data.get("bio_mode", "txt")).strip().lower()
|
bio_mode = str(data.get("bio_mode", "txt")).strip().lower()
|
||||||
website = str(data.get("website", "")).strip()
|
website = str(data.get("website", "")).strip()
|
||||||
location = str(data.get("location", "")).strip()
|
location = str(data.get("location", "")).strip()
|
||||||
|
status_message = str(data.get("status_message", "")).strip()
|
||||||
|
|
||||||
|
banner_attachment_id = data.get("banner_attachment_id")
|
||||||
|
if banner_attachment_id not in (None, ""):
|
||||||
|
try:
|
||||||
|
banner_attachment_id = int(banner_attachment_id)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return jsonify({"error": "Invalid banner attachment."}), 400
|
||||||
|
else:
|
||||||
|
banner_attachment_id = None
|
||||||
|
|
||||||
if len(display_name) > MAX_DISPLAY_NAME_LENGTH:
|
if len(display_name) > MAX_DISPLAY_NAME_LENGTH:
|
||||||
return jsonify({"error": "Display name is too long."}), 400
|
return jsonify({"error": "Display name is too long."}), 400
|
||||||
@ -4117,6 +4348,23 @@ def register_routes(app, ctx):
|
|||||||
return jsonify({"error": "Website is too long."}), 400
|
return jsonify({"error": "Website is too long."}), 400
|
||||||
if len(location) > MAX_LOCATION_LENGTH:
|
if len(location) > MAX_LOCATION_LENGTH:
|
||||||
return jsonify({"error": "Location is too long."}), 400
|
return jsonify({"error": "Location is too long."}), 400
|
||||||
|
if len(status_message) > 160:
|
||||||
|
return jsonify({"error": "Status message is too long."}), 400
|
||||||
|
|
||||||
|
if banner_attachment_id is not None:
|
||||||
|
with get_db() as db:
|
||||||
|
attachment = db.execute(
|
||||||
|
"""
|
||||||
|
SELECT id, uploader_user_id
|
||||||
|
FROM attachments
|
||||||
|
WHERE id = ?
|
||||||
|
""",
|
||||||
|
(banner_attachment_id,),
|
||||||
|
).fetchone()
|
||||||
|
if not attachment:
|
||||||
|
return jsonify({"error": "Banner attachment not found."}), 404
|
||||||
|
if attachment["uploader_user_id"] != user["id"]:
|
||||||
|
return jsonify({"error": "You can only use your own uploaded image."}), 403
|
||||||
|
|
||||||
db_write(
|
db_write(
|
||||||
"""
|
"""
|
||||||
@ -4128,6 +4376,8 @@ def register_routes(app, ctx):
|
|||||||
bio_mode = ?,
|
bio_mode = ?,
|
||||||
website = ?,
|
website = ?,
|
||||||
location = ?,
|
location = ?,
|
||||||
|
status_message = ?,
|
||||||
|
banner_attachment_id = ?,
|
||||||
updated_at = ?
|
updated_at = ?
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
""",
|
""",
|
||||||
@ -4138,6 +4388,8 @@ def register_routes(app, ctx):
|
|||||||
bio_mode,
|
bio_mode,
|
||||||
website,
|
website,
|
||||||
location,
|
location,
|
||||||
|
status_message,
|
||||||
|
banner_attachment_id,
|
||||||
now_iso(),
|
now_iso(),
|
||||||
user["id"],
|
user["id"],
|
||||||
),
|
),
|
||||||
@ -4152,7 +4404,8 @@ def register_routes(app, ctx):
|
|||||||
role,
|
role,
|
||||||
status,
|
status,
|
||||||
restricted_until,
|
restricted_until,
|
||||||
created_at
|
created_at,
|
||||||
|
last_login_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
""",
|
""",
|
||||||
@ -4178,7 +4431,6 @@ def register_routes(app, ctx):
|
|||||||
(user["id"],),
|
(user["id"],),
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
|
|
||||||
settings_row = db.execute(
|
settings_row = db.execute(
|
||||||
"""
|
"""
|
||||||
SELECT
|
SELECT
|
||||||
@ -4187,7 +4439,9 @@ def register_routes(app, ctx):
|
|||||||
profile_background_color,
|
profile_background_color,
|
||||||
profile_banner_color,
|
profile_banner_color,
|
||||||
profile_visibility,
|
profile_visibility,
|
||||||
last_active_visibility
|
last_active_visibility,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge
|
||||||
FROM user_settings
|
FROM user_settings
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
""",
|
""",
|
||||||
@ -4210,7 +4464,8 @@ def register_routes(app, ctx):
|
|||||||
role,
|
role,
|
||||||
status,
|
status,
|
||||||
restricted_until,
|
restricted_until,
|
||||||
created_at
|
created_at,
|
||||||
|
last_login_at
|
||||||
FROM users
|
FROM users
|
||||||
WHERE username = ?
|
WHERE username = ?
|
||||||
""",
|
""",
|
||||||
@ -4247,7 +4502,9 @@ def register_routes(app, ctx):
|
|||||||
profile_background_color,
|
profile_background_color,
|
||||||
profile_banner_color,
|
profile_banner_color,
|
||||||
profile_visibility,
|
profile_visibility,
|
||||||
last_active_visibility
|
last_active_visibility,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge
|
||||||
FROM user_settings
|
FROM user_settings
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
""",
|
""",
|
||||||
@ -4274,6 +4531,9 @@ def register_routes(app, ctx):
|
|||||||
profile_banner_color,
|
profile_banner_color,
|
||||||
profile_visibility,
|
profile_visibility,
|
||||||
last_active_visibility,
|
last_active_visibility,
|
||||||
|
presence_mode,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge,
|
||||||
updated_at
|
updated_at
|
||||||
FROM user_settings
|
FROM user_settings
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
@ -4281,7 +4541,6 @@ def register_routes(app, ctx):
|
|||||||
(user["id"],),
|
(user["id"],),
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
|
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"settings": {
|
"settings": {
|
||||||
@ -4293,6 +4552,9 @@ def register_routes(app, ctx):
|
|||||||
"profile_banner_color": row["profile_banner_color"],
|
"profile_banner_color": row["profile_banner_color"],
|
||||||
"profile_visibility": row["profile_visibility"],
|
"profile_visibility": row["profile_visibility"],
|
||||||
"last_active_visibility": row["last_active_visibility"],
|
"last_active_visibility": row["last_active_visibility"],
|
||||||
|
"presence_mode": row["presence_mode"],
|
||||||
|
"dm_layout_mode": row["dm_layout_mode"],
|
||||||
|
"show_presence_badge": bool(row["show_presence_badge"]),
|
||||||
"updated_at": row["updated_at"],
|
"updated_at": row["updated_at"],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4320,15 +4582,36 @@ def register_routes(app, ctx):
|
|||||||
name_color = data.get("name_color")
|
name_color = data.get("name_color")
|
||||||
custom_css = str(data.get("custom_css", ""))
|
custom_css = str(data.get("custom_css", ""))
|
||||||
theme_mode = str(data.get("theme_mode", "dark")).strip().lower()
|
theme_mode = str(data.get("theme_mode", "dark")).strip().lower()
|
||||||
|
profile_background_color = data.get("profile_background_color")
|
||||||
|
profile_banner_color = data.get("profile_banner_color")
|
||||||
|
profile_visibility = str(data.get("profile_visibility", "public")).strip().lower()
|
||||||
|
last_active_visibility = str(data.get("last_active_visibility", "everyone")).strip().lower()
|
||||||
|
presence_mode = str(data.get("presence_mode", "online")).strip().lower()
|
||||||
|
dm_layout_mode = str(data.get("dm_layout_mode", "cards")).strip().lower()
|
||||||
|
show_presence_badge_raw = data.get("show_presence_badge", True)
|
||||||
|
|
||||||
if not valid_hex_color(accent_color):
|
if not valid_hex_color(accent_color):
|
||||||
return jsonify({"error": "Invalid accent color."}), 400
|
return jsonify({"error": "Invalid accent color."}), 400
|
||||||
if name_color not in (None, "") and not valid_hex_color(name_color):
|
if name_color not in (None, "") and not valid_hex_color(name_color):
|
||||||
return jsonify({"error": "Invalid name color."}), 400
|
return jsonify({"error": "Invalid name color."}), 400
|
||||||
|
if profile_background_color not in (None, "") and not valid_hex_color(profile_background_color):
|
||||||
|
return jsonify({"error": "Invalid profile background color."}), 400
|
||||||
|
if profile_banner_color not in (None, "") and not valid_hex_color(profile_banner_color):
|
||||||
|
return jsonify({"error": "Invalid profile banner color."}), 400
|
||||||
if len(custom_css) > MAX_CUSTOM_CSS_LENGTH:
|
if len(custom_css) > MAX_CUSTOM_CSS_LENGTH:
|
||||||
return jsonify({"error": "Custom CSS is too long."}), 400
|
return jsonify({"error": "Custom CSS is too long."}), 400
|
||||||
if theme_mode not in THEME_MODES:
|
if theme_mode not in THEME_MODES:
|
||||||
return jsonify({"error": "Invalid theme mode."}), 400
|
return jsonify({"error": "Invalid theme mode."}), 400
|
||||||
|
if profile_visibility not in PROFILE_VISIBILITIES:
|
||||||
|
return jsonify({"error": "Invalid profile visibility."}), 400
|
||||||
|
if last_active_visibility not in LAST_ACTIVE_VISIBILITIES:
|
||||||
|
return jsonify({"error": "Invalid last active visibility."}), 400
|
||||||
|
if presence_mode not in PRESENCE_MODES:
|
||||||
|
return jsonify({"error": "Invalid presence mode."}), 400
|
||||||
|
if dm_layout_mode not in DM_LAYOUT_MODES:
|
||||||
|
return jsonify({"error": "Invalid dm layout mode."}), 400
|
||||||
|
|
||||||
|
show_presence_badge = 1 if bool(show_presence_badge_raw) else 0
|
||||||
|
|
||||||
db_write(
|
db_write(
|
||||||
"""
|
"""
|
||||||
@ -4342,6 +4625,9 @@ def register_routes(app, ctx):
|
|||||||
profile_banner_color = ?,
|
profile_banner_color = ?,
|
||||||
profile_visibility = ?,
|
profile_visibility = ?,
|
||||||
last_active_visibility = ?,
|
last_active_visibility = ?,
|
||||||
|
presence_mode = ?,
|
||||||
|
dm_layout_mode = ?,
|
||||||
|
show_presence_badge = ?,
|
||||||
updated_at = ?
|
updated_at = ?
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
""",
|
""",
|
||||||
@ -4350,10 +4636,13 @@ def register_routes(app, ctx):
|
|||||||
normalized_hex_color(name_color) if name_color else None,
|
normalized_hex_color(name_color) if name_color else None,
|
||||||
custom_css,
|
custom_css,
|
||||||
theme_mode,
|
theme_mode,
|
||||||
data.get("profile_background_color"),
|
normalized_hex_color(profile_background_color) if profile_background_color else None,
|
||||||
data.get("profile_banner_color"),
|
normalized_hex_color(profile_banner_color) if profile_banner_color else None,
|
||||||
str(data.get("profile_visibility", "public")).strip().lower(),
|
profile_visibility,
|
||||||
str(data.get("last_active_visibility", "mutuals")).strip().lower(),
|
last_active_visibility,
|
||||||
|
presence_mode,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge,
|
||||||
now_iso(),
|
now_iso(),
|
||||||
user["id"],
|
user["id"],
|
||||||
),
|
),
|
||||||
@ -4371,6 +4660,9 @@ def register_routes(app, ctx):
|
|||||||
profile_banner_color,
|
profile_banner_color,
|
||||||
profile_visibility,
|
profile_visibility,
|
||||||
last_active_visibility,
|
last_active_visibility,
|
||||||
|
presence_mode,
|
||||||
|
dm_layout_mode,
|
||||||
|
show_presence_badge,
|
||||||
updated_at
|
updated_at
|
||||||
FROM user_settings
|
FROM user_settings
|
||||||
WHERE user_id = ?
|
WHERE user_id = ?
|
||||||
@ -4379,7 +4671,53 @@ def register_routes(app, ctx):
|
|||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
audit("settings_updated", user["id"], "user", str(user["id"]))
|
audit("settings_updated", user["id"], "user", str(user["id"]))
|
||||||
return jsonify({"settings": dict(row)})
|
return jsonify(
|
||||||
|
{
|
||||||
|
"settings": {
|
||||||
|
**dict(row),
|
||||||
|
"show_presence_badge": bool(row["show_presence_badge"]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route("/api/scheduled-messages", methods=["POST"])
|
||||||
|
def api_create_scheduled_message():
|
||||||
|
if not csrf_valid():
|
||||||
|
return jsonify({"error": "Security token expired.", "code": "csrf"}), 403
|
||||||
|
|
||||||
|
user, error = require_writable_user()
|
||||||
|
if error:
|
||||||
|
return error
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = safe_json()
|
||||||
|
except ValueError as error:
|
||||||
|
return jsonify({"error": str(error)}), 400
|
||||||
|
|
||||||
|
text = str(data.get("text", "")).strip()
|
||||||
|
deliver_at = str(data.get("deliver_at", "")).strip()
|
||||||
|
scope_kind = str(data.get("scope_kind", "")).strip()
|
||||||
|
scope_id = data.get("scope_id")
|
||||||
|
|
||||||
|
if not text:
|
||||||
|
return jsonify({"error": "Scheduled message text is required."}), 400
|
||||||
|
if len(text) > MAX_MESSAGE_LENGTH:
|
||||||
|
return jsonify({"error": "Scheduled message is too long."}), 400
|
||||||
|
if not deliver_at:
|
||||||
|
return jsonify({"error": "deliver_at is required."}), 400
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
{
|
||||||
|
"status": "stubbed",
|
||||||
|
"scheduled_message": {
|
||||||
|
"id": 0,
|
||||||
|
"text": text,
|
||||||
|
"deliver_at": deliver_at,
|
||||||
|
"scope_kind": scope_kind,
|
||||||
|
"scope_id": scope_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
), 201
|
||||||
|
|
||||||
@app.route("/api/dms")
|
@app.route("/api/dms")
|
||||||
def api_list_dms():
|
def api_list_dms():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user