Skip to content

Commit 40aca6c

Browse files
hellcpjwise
authored andcommitted
Add timeline token to the apps table
Signed-off-by: Stasia Michalska <[email protected]>
1 parent e6e221e commit 40aca6c

File tree

4 files changed

+83
-7
lines changed

4 files changed

+83
-7
lines changed

appstore/api.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66

77
from sqlalchemy.orm.exc import NoResultFound
88

9-
from appstore.utils import jsonify_app, asset_fallback, generate_image_url
9+
from appstore.utils import jsonify_app, asset_fallback, generate_image_url, get_access_token
1010
from .models import App, Collection, HomeBanners, Category, db, Release
11+
from .settings import config
1112

1213
parent_app = None
1314
api = Blueprint('api', __name__)
@@ -114,6 +115,27 @@ def apps_by_collection(collection, app_type):
114115
return generate_app_response(apps, sort_override=sort_override)
115116

116117

118+
@api.route('/apps/by_token/<timeline_token>')
119+
def apps_by_token(timeline_token):
120+
secret = get_access_token()
121+
if secret != config['SECRET_KEY']:
122+
abort(401)
123+
if timeline_token == "":
124+
abort(404)
125+
126+
try:
127+
app = App.query.filter(App.timeline_token == timeline_token).one()
128+
except NoResultFound:
129+
abort(404)
130+
return
131+
132+
result = {
133+
"app_uuid": app.app_uuid
134+
}
135+
136+
return jsonify(result)
137+
138+
117139
@api.route('/applications/<app_id>/changelog')
118140
def changelogs_by_id(app_id):
119141
try:

appstore/developer_portal_api.py

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import traceback
33
import datetime
4+
import secrets
45

56
from algoliasearch import algoliasearch
67
from flask import Blueprint, jsonify, abort, request
@@ -152,8 +153,10 @@ def submit_new_app():
152153
), 400
153154

154155
app_is_timeline_enabled = False
156+
timeline_token = None
155157
if 'timeline_enabled' in params and params['timeline_enabled'] == 'true':
156158
app_is_timeline_enabled = True
159+
timeline_token = secrets.token_urlsafe(32)
157160

158161
# Remove any platforms with no screenshots
159162
screenshots = {k: v for k, v in screenshots.items() if v}
@@ -179,6 +182,7 @@ def submit_new_app():
179182
title=params['title'],
180183
type=params['type'],
181184
timeline_enabled=app_is_timeline_enabled,
185+
timeline_token=timeline_token,
182186
website=params['website'] if 'website' in params else "",
183187
)
184188
db.session.add(app_obj)
@@ -218,12 +222,14 @@ def update_app_fields(app_id):
218222
"category": str,
219223
"website": str,
220224
"source": str,
221-
"visible": bool
225+
"visible": bool,
226+
"timeline_enabled": bool,
227+
"timeline_token": None
222228
}
223229

224230
# Check all valid passed fields are correct type
225231
for x in req:
226-
if (x in allowed_fields_type_map) and (not type(x) == allowed_fields_type_map[x]):
232+
if (x in allowed_fields_type_map) and (not type(req[x]) == allowed_fields_type_map[x]):
227233
return jsonify(error=f"Invalid value for field '{x}'", e=f"invalid.field.{x}"), 400
228234

229235

@@ -240,8 +246,6 @@ def update_app_fields(app_id):
240246
# Check any enum fields
241247
if "category" in req and not is_valid_category(req["category"]):
242248
return jsonify(error="Invalid value for field: category", e="invalid.field.category"), 400
243-
if "visible" in req and not (req["visible"].lower() == "true" or req["visible"].lower() == "false"):
244-
return jsonify(error="Invalid value for field: visible", e="invalid.field.visible"), 400
245249

246250
# Disallow change face category
247251
if "category" in req and app.category == "Faces":
@@ -250,7 +254,14 @@ def update_app_fields(app_id):
250254
# Check title length
251255
if "title" in req and len(req["title"]) > 45:
252256
return jsonify(error="Title must be less than 45 characters", e="invalid.field.title"), 400
253-
257+
258+
# Create a timeline token when enabling the timeline
259+
if "timeline_enabled" in req:
260+
if not req["timeline_enabled"]:
261+
req["timeline_token"] = None
262+
elif app.timeline_token == None:
263+
req["timeline_token"] = secrets.token_urlsafe(32)
264+
254265
# Update the app
255266
for x in req:
256267
setattr(app, x, req[x])
@@ -332,7 +343,25 @@ def submit_new_release(app_id):
332343
print("Discord is being weird")
333344

334345
return jsonify(success=True)
335-
346+
347+
@devportal_api.route('/app/<app_id>/timeline_token')
348+
def apps_timeline_token(app_id):
349+
try:
350+
app = App.query.filter(App.id == app_id).one()
351+
except NoResultFound:
352+
abort(404)
353+
return
354+
355+
# Check we own the app
356+
if not is_users_developer_id(app.developer_id):
357+
return jsonify(error="You do not have permission to access the token", e="permission.denied"), 403
358+
359+
result = {
360+
"timeline_token": app.timeline_token
361+
}
362+
363+
return jsonify(result)
364+
336365
# Screenshots
337366
@devportal_api.route('/app/<app_id>/screenshots')
338367
def missing_platform(app_id):

appstore/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class App(db.Model):
7575
type = db.Column(db.String)
7676
website = db.Column(db.String)
7777
visible = db.Column(db.Boolean, default=True, server_default='TRUE', nullable=False)
78+
timeline_token = db.Column(db.String, index=True)
7879

7980

8081
category_banner_apps = Table('category_banner_apps', db.Model.metadata,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Add apps timeline_token
2+
3+
Revision ID: ec9b0b6d8795
4+
Revises: ddb71f0a1c96
5+
Create Date: 2025-11-08 13:25:52.990174
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = 'ec9b0b6d8795'
14+
down_revision = 'ddb71f0a1c96'
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.add_column('apps', sa.Column('timeline_token', sa.String(), nullable=True))
21+
22+
23+
def downgrade():
24+
op.drop_column('apps', 'timeline_token')

0 commit comments

Comments
 (0)