Skip to content

Commit d8593ea

Browse files
Improve admin webui (#112)
* fix columns and filters - add formatters to remove milliseconds on dates - add column labels to be used with filters - add new filters for version and build views * fix screenshot management - remove edit function - fix file removal with row deletion * fix Babel initialisation * add service view and api check - add service view to admin interface - add service check on package upload * add and maintain md5 hashes - add a functions to get md5 hash in build model and spk - use function in build model when uploading build - use function in spk when signing/unsigning spk * remove builds from architecture create form * fix build environment and model - fix alembic setup environment - update model to match database - fix default sort for screenshot * Update nas test for major_version check * add major_version check - identify the major DSM version based on a closest match to the build - filter package versions based on match to major DSM version - include earlier "noarch" package version when major DSM version < 6 * fix download counter - rewrite catalog download links using md5 hashes for id - allow downloads of noarch builds to pass arch checks - rewrite nas tests for new url structure * Fix depopulate db function * Revert "fix download counter" This reverts commit bea7718. * Amend major_version check - Add type column to Firmware table - Increase length of version column - Filter by type for closest firmware when getting catalog - Update populate_db with firmware type * add validators for firmware input * fix Popped wrong app context. * fix 500 page on users: 'NoneType' object has no attribute 'strftime' BaseModelView.index_view() got an unexpected keyword argument 'cls' Flask-SQLAlchemy uses a custom formatter to handle date formatting when displaying data in the templates. It dosn't support overriding the value. * fix column formatting --------- Co-authored-by: publicarray <[email protected]>
1 parent 2db02f3 commit d8593ea

16 files changed

+275
-40
lines changed

.flake8

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[flake8]
22
max-line-length = 88
33
extend-ignore = E203
4-
per-file-ignores = __init__.py:F401 spkrepo/app.py:F841
4+
per-file-ignores = __init__.py:F401
55
exclude =
66
docs/*
77
migrations/*

migrations/alembic.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[alembic]
2-
script_location = .
2+
script_location = ./migrations
33

44
[loggers]
55
keys = root,sqlalchemy,alembic

migrations/env.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
config = context.config
99
fileConfig(config.config_file_name)
1010

11-
1211
config.set_main_option(
1312
"sqlalchemy.url", current_app.config.get("SQLALCHEMY_DATABASE_URI")
1413
)

migrations/versions/dc7687894ba7_increase_field_sizes.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414

1515
def upgrade():
16-
# ### commands auto generated by Alembic - please adjust! ###
1716
op.alter_column(
1817
"version",
1918
"conf_dependencies",
@@ -42,11 +41,9 @@ def upgrade():
4241
type_=sa.UnicodeText(),
4342
existing_nullable=True,
4443
)
45-
# ### end Alembic commands ###
4644

4745

4846
def downgrade():
49-
# ### commands auto generated by Alembic - please adjust! ###
5047
op.alter_column(
5148
"version",
5249
"conf_resource",
@@ -75,4 +72,3 @@ def downgrade():
7572
type_=sa.VARCHAR(length=255),
7673
existing_nullable=True,
7774
)
78-
# ### end Alembic commands ###
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
"""Add firmware type and increase version length
2+
3+
Revision ID: f95855ce9471
4+
Revises: 76d559b4e873
5+
Create Date: 2024-01-15 13:58:34.160242
6+
7+
"""
8+
revision = "f95855ce9471"
9+
down_revision = "76d559b4e873"
10+
11+
import sqlalchemy as sa
12+
from alembic import op
13+
14+
15+
def upgrade():
16+
op.add_column("firmware", sa.Column("type", sa.Unicode(length=4)))
17+
# Set type based on version
18+
op.execute(
19+
"""
20+
UPDATE firmware
21+
SET type = CASE
22+
WHEN version LIKE '1.%' THEN 'srm'
23+
ELSE 'dsm'
24+
END
25+
"""
26+
)
27+
# Modify the column to be NOT NULL after setting the values
28+
op.alter_column("firmware", "type", nullable=False)
29+
30+
op.alter_column(
31+
"firmware",
32+
"version",
33+
existing_type=sa.VARCHAR(length=3),
34+
type_=sa.Unicode(length=4),
35+
existing_nullable=False,
36+
)
37+
38+
39+
def downgrade():
40+
op.alter_column(
41+
"firmware",
42+
"version",
43+
existing_type=sa.Unicode(length=4),
44+
type_=sa.VARCHAR(length=3),
45+
existing_nullable=False,
46+
)
47+
op.drop_column("firmware", "type")

spkrepo/app.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
import jinja2
33
from flask import Flask
44
from flask_admin import Admin
5-
from flask_babel import Babel
65
from wtforms import HiddenField
76

87
from . import config as default_config
98
from .cli import spkrepo as spkrepo_cli
10-
from .ext import cache, db, debug_toolbar, mail, migrate, security
9+
from .ext import babel, cache, db, debug_toolbar, mail, migrate, security
1110
from .models import user_datastore
1211
from .views import (
1312
ArchitectureView,
@@ -16,6 +15,7 @@
1615
IndexView,
1716
PackageView,
1817
ScreenshotView,
18+
ServiceView,
1919
SpkrepoConfirmRegisterForm,
2020
UserView,
2121
VersionView,
@@ -53,18 +53,19 @@ def create_app(config=None, register_blueprints=True, init_admin=True):
5353
admin.add_view(UserView())
5454
admin.add_view(ArchitectureView())
5555
admin.add_view(FirmwareView())
56+
admin.add_view(ServiceView())
5657
admin.add_view(ScreenshotView())
5758
admin.add_view(PackageView())
5859
admin.add_view(VersionView())
5960
admin.add_view(BuildView())
6061
admin.init_app(app)
6162

62-
# Initialize Flask-Babel
63-
babel = Babel(app)
64-
6563
# Commands
6664
app.cli.add_command(spkrepo_cli)
6765

66+
# Flask-Babel
67+
babel.init_app(app)
68+
6869
# SQLAlchemy
6970
db.init_app(app)
7071

spkrepo/cli.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,15 @@ def depopulate_db():
180180
from spkrepo.models import Package
181181

182182
for package in Package.query.all():
183-
shutil.rmtree(os.path.join(current_app.config["DATA_PATH"], package.name))
183+
# Delete the package and its associated versions and builds
184184
db.session.delete(package)
185+
186+
# Remove the directory associated with the package (if it exists)
187+
shutil.rmtree(
188+
os.path.join(current_app.config["DATA_PATH"], package.name),
189+
ignore_errors=True,
190+
)
191+
185192
db.session.commit()
186193

187194

spkrepo/ext.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
# -*- coding: utf-8 -*-
2+
from flask_babel import Babel
23
from flask_caching import Cache
34
from flask_debugtoolbar import DebugToolbarExtension
45
from flask_mail import Mail
56
from flask_migrate import Migrate
67
from flask_security import Security
78
from flask_sqlalchemy import SQLAlchemy
89

10+
# Flask-Babel
11+
babel = Babel()
12+
913
# Cache
1014
cache = Cache()
1115

spkrepo/models.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# -*- coding: utf-8 -*-
2+
import hashlib
23
import io
34
import os
45
import shutil
@@ -133,8 +134,9 @@ class Firmware(db.Model):
133134

134135
# Columns
135136
id = db.Column(db.Integer, primary_key=True)
136-
version = db.Column(db.Unicode(3), nullable=False)
137+
version = db.Column(db.Unicode(4), nullable=False)
137138
build = db.Column(db.Integer, unique=True, nullable=False)
139+
type = db.Column(db.Unicode(4), nullable=False)
138140

139141
@classmethod
140142
def find(cls, build):
@@ -328,7 +330,7 @@ class Build(db.Model):
328330
publisher_user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
329331
checksum = db.Column(db.Unicode(32))
330332
extract_size = db.Column(db.Integer)
331-
path = db.Column(db.Unicode(100))
333+
path = db.Column(db.Unicode(2048))
332334
md5 = db.Column(db.Unicode(32))
333335
insert_date = db.Column(db.DateTime, default=db.func.now(), nullable=False)
334336
active = db.Column(db.Boolean(), default=False, nullable=False)
@@ -343,7 +345,11 @@ class Build(db.Model):
343345
)
344346
firmware = db.relationship("Firmware", lazy=False)
345347
publisher = db.relationship("User", foreign_keys=[publisher_user_id])
346-
downloads = db.relationship("Download", back_populates="build")
348+
downloads = db.relationship(
349+
"Download",
350+
back_populates="build",
351+
cascade="save-update, merge, delete, delete-orphan",
352+
)
347353

348354
@classmethod
349355
def generate_filename(cls, package, version, firmware, architectures):
@@ -360,6 +366,24 @@ def save(self, stream):
360366
) as f:
361367
f.write(stream.read())
362368

369+
def calculate_md5(self):
370+
if not self.path:
371+
raise ValueError("Path cannot be empty.")
372+
373+
file_path = os.path.join(current_app.config["DATA_PATH"], self.path)
374+
375+
if not os.path.exists(file_path):
376+
raise FileNotFoundError(f"File not found at path: {file_path}")
377+
378+
if self.md5 is None:
379+
with io.open(file_path, "rb") as f:
380+
md5_hash = hashlib.md5()
381+
for chunk in iter(lambda: f.read(4096), b""):
382+
md5_hash.update(chunk)
383+
return md5_hash.hexdigest()
384+
385+
return self.md5
386+
363387
def _after_insert(self):
364388
assert os.path.exists(os.path.join(current_app.config["DATA_PATH"], self.path))
365389

spkrepo/tests/common.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,7 @@ def create_spk(self, create, extracted, **kwargs):
281281
with create_spk(self) as spk_stream:
282282
self.save(spk_stream)
283283
if self.md5 is None:
284-
spk_stream.seek(0)
285-
self.md5 = hashlib.md5(spk_stream.read()).hexdigest()
284+
self.md5 = self.calculate_md5()
286285
spk_stream.close()
287286

288287
@classmethod

0 commit comments

Comments
 (0)