Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve admin webui #112

Merged
merged 17 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[flake8]
max-line-length = 88
extend-ignore = E203
per-file-ignores = __init__.py:F401 spkrepo/app.py:F841
per-file-ignores = __init__.py:F401
exclude =
docs/*
migrations/*
2 changes: 1 addition & 1 deletion migrations/alembic.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[alembic]
script_location = .
script_location = ./migrations

[loggers]
keys = root,sqlalchemy,alembic
Expand Down
1 change: 0 additions & 1 deletion migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
config = context.config
fileConfig(config.config_file_name)


config.set_main_option(
"sqlalchemy.url", current_app.config.get("SQLALCHEMY_DATABASE_URI")
)
Expand Down
4 changes: 0 additions & 4 deletions migrations/versions/dc7687894ba7_increase_field_sizes.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column(
"version",
"conf_dependencies",
Expand Down Expand Up @@ -42,11 +41,9 @@ def upgrade():
type_=sa.UnicodeText(),
existing_nullable=True,
)
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column(
"version",
"conf_resource",
Expand Down Expand Up @@ -75,4 +72,3 @@ def downgrade():
type_=sa.VARCHAR(length=255),
existing_nullable=True,
)
# ### end Alembic commands ###
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""Add firmware type and increase version length

Revision ID: f95855ce9471
Revises: 76d559b4e873
Create Date: 2024-01-15 13:58:34.160242

"""
revision = "f95855ce9471"
down_revision = "76d559b4e873"

import sqlalchemy as sa
from alembic import op


def upgrade():
op.add_column("firmware", sa.Column("type", sa.Unicode(length=4)))
# Set type based on version
op.execute(
"""
UPDATE firmware
SET type = CASE
WHEN version LIKE '1.%' THEN 'srm'
ELSE 'dsm'
END
"""
)
# Modify the column to be NOT NULL after setting the values
op.alter_column("firmware", "type", nullable=False)

op.alter_column(
"firmware",
"version",
existing_type=sa.VARCHAR(length=3),
type_=sa.Unicode(length=4),
existing_nullable=False,
)


def downgrade():
op.alter_column(
"firmware",
"version",
existing_type=sa.Unicode(length=4),
type_=sa.VARCHAR(length=3),
existing_nullable=False,
)
op.drop_column("firmware", "type")
11 changes: 6 additions & 5 deletions spkrepo/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
import jinja2
from flask import Flask
from flask_admin import Admin
from flask_babel import Babel
from wtforms import HiddenField

from . import config as default_config
from .cli import spkrepo as spkrepo_cli
from .ext import cache, db, debug_toolbar, mail, migrate, security
from .ext import babel, cache, db, debug_toolbar, mail, migrate, security
from .models import user_datastore
from .views import (
ArchitectureView,
Expand All @@ -16,6 +15,7 @@
IndexView,
PackageView,
ScreenshotView,
ServiceView,
SpkrepoConfirmRegisterForm,
UserView,
VersionView,
Expand Down Expand Up @@ -53,18 +53,19 @@ def create_app(config=None, register_blueprints=True, init_admin=True):
admin.add_view(UserView())
admin.add_view(ArchitectureView())
admin.add_view(FirmwareView())
admin.add_view(ServiceView())
admin.add_view(ScreenshotView())
admin.add_view(PackageView())
admin.add_view(VersionView())
admin.add_view(BuildView())
admin.init_app(app)

# Initialize Flask-Babel
babel = Babel(app)

# Commands
app.cli.add_command(spkrepo_cli)

# Flask-Babel
babel.init_app(app)

# SQLAlchemy
db.init_app(app)

Expand Down
9 changes: 8 additions & 1 deletion spkrepo/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,15 @@ def depopulate_db():
from spkrepo.models import Package

for package in Package.query.all():
shutil.rmtree(os.path.join(current_app.config["DATA_PATH"], package.name))
# Delete the package and its associated versions and builds
db.session.delete(package)

# Remove the directory associated with the package (if it exists)
shutil.rmtree(
os.path.join(current_app.config["DATA_PATH"], package.name),
ignore_errors=True,
)

db.session.commit()


Expand Down
4 changes: 4 additions & 0 deletions spkrepo/ext.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# -*- coding: utf-8 -*-
from flask_babel import Babel
from flask_caching import Cache
from flask_debugtoolbar import DebugToolbarExtension
from flask_mail import Mail
from flask_migrate import Migrate
from flask_security import Security
from flask_sqlalchemy import SQLAlchemy

# Flask-Babel
babel = Babel()

# Cache
cache = Cache()

Expand Down
30 changes: 27 additions & 3 deletions spkrepo/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import hashlib
import io
import os
import shutil
Expand Down Expand Up @@ -133,8 +134,9 @@ class Firmware(db.Model):

# Columns
id = db.Column(db.Integer, primary_key=True)
version = db.Column(db.Unicode(3), nullable=False)
version = db.Column(db.Unicode(4), nullable=False)
build = db.Column(db.Integer, unique=True, nullable=False)
type = db.Column(db.Unicode(4), nullable=False)

@classmethod
def find(cls, build):
Expand Down Expand Up @@ -328,7 +330,7 @@ class Build(db.Model):
publisher_user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
checksum = db.Column(db.Unicode(32))
extract_size = db.Column(db.Integer)
path = db.Column(db.Unicode(100))
path = db.Column(db.Unicode(2048))
md5 = db.Column(db.Unicode(32))
insert_date = db.Column(db.DateTime, default=db.func.now(), nullable=False)
active = db.Column(db.Boolean(), default=False, nullable=False)
Expand All @@ -343,7 +345,11 @@ class Build(db.Model):
)
firmware = db.relationship("Firmware", lazy=False)
publisher = db.relationship("User", foreign_keys=[publisher_user_id])
downloads = db.relationship("Download", back_populates="build")
downloads = db.relationship(
"Download",
back_populates="build",
cascade="save-update, merge, delete, delete-orphan",
)

@classmethod
def generate_filename(cls, package, version, firmware, architectures):
Expand All @@ -360,6 +366,24 @@ def save(self, stream):
) as f:
f.write(stream.read())

def calculate_md5(self):
if not self.path:
raise ValueError("Path cannot be empty.")

file_path = os.path.join(current_app.config["DATA_PATH"], self.path)

if not os.path.exists(file_path):
raise FileNotFoundError(f"File not found at path: {file_path}")

if self.md5 is None:
with io.open(file_path, "rb") as f:
md5_hash = hashlib.md5()
for chunk in iter(lambda: f.read(4096), b""):
md5_hash.update(chunk)
return md5_hash.hexdigest()

return self.md5

def _after_insert(self):
assert os.path.exists(os.path.join(current_app.config["DATA_PATH"], self.path))

Expand Down
3 changes: 1 addition & 2 deletions spkrepo/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,7 @@ def create_spk(self, create, extracted, **kwargs):
with create_spk(self) as spk_stream:
self.save(spk_stream)
if self.md5 is None:
spk_stream.seek(0)
self.md5 = hashlib.md5(spk_stream.read()).hexdigest()
self.md5 = self.calculate_md5()
spk_stream.close()

@classmethod
Expand Down
21 changes: 19 additions & 2 deletions spkrepo/tests/test_nas.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ def test_stable_build_active_stable(self):
catalog[0], build, data, dict(arch="88f628x", build="1594")
)

def test_stable_build_active_stable_5004(self):
def test_stable_noarch_build_active_stable_5004(self):
build = BuildFactory(
active=True,
version__report_url=None,
architectures=[Architecture.find("88f6281", syno=True)],
architectures=[Architecture.find("noarch", syno=True)],
firmware=Firmware.find(1594),
)
db.session.commit()
Expand All @@ -247,6 +247,23 @@ def test_stable_build_active_stable_5004(self):
catalog["packages"][0], build, data, dict(arch="88f628x", build="5004")
)

def test_stable_arch_build_active_stable_5004(self):
BuildFactory(
active=True,
version__report_url=None,
architectures=[Architecture.find("88f6281", syno=True)],
firmware=Firmware.find(1594),
)
db.session.commit()
data = dict(arch="88f6281", build="5004", language="enu")
response = self.client.post(url_for("nas.catalog"), data=data)
self.assert200(response)
self.assertHeader(response, "Content-Type", "application/json")
catalog = json.loads(response.data.decode())
self.assertIn("packages", catalog)
self.assertIn("keyrings", catalog)
self.assertEqual(len(catalog["packages"]), 0)

def test_stable_build_active_stable_download_count(self):
package = PackageFactory()
build = BuildFactory(
Expand Down
21 changes: 20 additions & 1 deletion spkrepo/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class SPK(object):
#: Regex for files in conf
conf_filename_re = re.compile(r"^conf/.+$")

#: Regex for firmware input
firmware_version_re = re.compile(r"^\d+\.\d$")
firmware_type_re = re.compile(r"^([a-z]){3,}$")

def __init__(self, stream):
self.info = {}
self.icons = {}
Expand Down Expand Up @@ -345,6 +349,18 @@ def unsign(self):
self.stream.truncate()
self.stream.seek(0)

def calculate_md5(self):
md5_hash = hashlib.md5()

# Ensure the stream position is at the beginning
self.stream.seek(0)

# Update MD5 hash directly from the stream
for chunk in iter(lambda: self.stream.read(4096), b""):
md5_hash.update(chunk)

return md5_hash.hexdigest()

def _generate_signature(self, stream, timestamp_url, gnupghome): # pragma: no cover
# generate the signature
gpg = gnupg.GPG(gnupghome=gnupghome)
Expand Down Expand Up @@ -386,7 +402,10 @@ def populate_db():
)
db.session.execute(
Firmware.__table__.insert().values(
[{"version": "3.1", "build": 1594}, {"version": "5.0", "build": 4458}]
[
{"version": "3.1", "build": 1594, "type": "dsm"},
{"version": "5.0", "build": 4458, "type": "dsm"},
]
)
)
db.session.execute(
Expand Down
1 change: 1 addition & 0 deletions spkrepo/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
IndexView,
PackageView,
ScreenshotView,
ServiceView,
UserView,
VersionView,
)
Expand Down
Loading
Loading