результаты админка
Gitea Actions Demo / build_and_push (push) Successful in 24m17s Details

This commit is contained in:
artem 2026-01-26 18:01:27 +03:00
parent 59758f17a3
commit 6a1bbb9a08
8 changed files with 116 additions and 2 deletions

View File

@ -8,10 +8,14 @@ from wtforms import fields, validators
from server.admin.auth import POOL, User
from server.admin.config import app, db_sync
from server.admin.views.attachments import AttachmentView
from server.admin.views.results import ResultsView
from server.admin.views.vote import VotesView
from server.config import get_app_config
from server.infra.db import AsyncDB
from server.modules.attachments import AtachmentService, DBAttachmentRepository, S3StorageDriver
from server.modules.attachments.repository.models import Attachment
from server.modules.rate.repository.models import Vote
from server.modules.recognizer.repository.models import ResultBeerds
login_manager = flask_login.LoginManager()
login_manager.init_app(app)
@ -119,5 +123,7 @@ if __name__ == "__main__":
)
admin.add_view(AttachmentView(Attachment, db_sync.session))
admin.add_view(ResultsView(ResultBeerds, db_sync.session))
admin.add_view(VotesView(Vote, db_sync.session))
app.run(debug=False, host="0.0.0.0", port=8000)

View File

@ -0,0 +1,38 @@
import flask_login
from flask import flash, redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
from markupsafe import Markup
# Create customized model view class
class ResultsView(ModelView):
can_edit = False
can_delete = False
can_create = False
column_default_sort = ("result.created_at", True)
def is_accessible(self):
"""Check if current user can access admin interface"""
return flask_login.current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
"""Redirect to login if not accessible"""
flash("Please login to access this page.", "danger")
return redirect(url_for("admin.login_view", next=request.url))
@staticmethod
def _list_thumbnail(view, _context, model, _name):
data = ""
data += f'<img src="/attachments{model.result.attachment.path}.original.jpg" width="100" />'
return Markup(data)
column_formatters = {
"path": _list_thumbnail,
}
column_list = [
"result",
"path",
"beerd",
]

View File

@ -0,0 +1,38 @@
import flask_login
from flask import flash, redirect, request, url_for
from flask_admin.contrib.sqla import ModelView
from markupsafe import Markup
class VotesView(ModelView):
can_edit = False
can_delete = False
can_create = False
column_default_sort = ("created_at", True)
def is_accessible(self):
"""Check if current user can access admin interface"""
return flask_login.current_user.is_authenticated
def inaccessible_callback(self, name, **kwargs):
"""Redirect to login if not accessible"""
flash("Please login to access this page.", "danger")
return redirect(url_for("admin.login_view", next=request.url))
@staticmethod
def _list_thumbnail(view, _context, model, _name):
data = ""
data += f'<img src="/attachments{model.attachment.path}.original.jpg" width="100" />'
return Markup(data)
column_formatters = {
"path": _list_thumbnail,
}
column_list = [
"created_at",
"path",
"beerd",
"rate",
]

View File

@ -17,3 +17,6 @@ class Beerds(UJsonMixin):
alias: str = field(metadata={"sa": Column(Text(), nullable=False)})
descriptions: str = field(metadata={"sa": Column(Text(), nullable=False)})
signs: dict | None = field(default=None, metadata={"sa": Column(JSON(), nullable=False)})
def __str__(self):
return self.name

View File

@ -9,10 +9,13 @@ from sqlalchemy import (
ForeignKeyConstraint,
String,
)
from sqlalchemy.orm import relationship
from server.config import get_app_config
from server.infra.db.db_mapper import mapper_registry
from server.modules.rate import domain
from server.modules.attachments.repository.attachments import Attachment
from server.modules.descriptions.repository.models import Beerds
@mapper_registry.mapped
@ -25,6 +28,12 @@ class Vote(UJsonMixin):
ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "votes_beerd_id_fk"),
)
__mapper_args__ = {
"properties": {
"beerd": relationship(Beerds, foreign_keys="Vote.beerd_id"),
"attachment": relationship(Attachment, foreign_keys="Vote.attachment_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)})
beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)})

View File

@ -8,8 +8,11 @@ from sqlalchemy import (
ForeignKeyConstraint,
String,
)
from sqlalchemy.orm import relationship
from server.infra.db.db_mapper import mapper_registry
from server.modules.attachments.repository.attachments import Attachment
from server.modules.descriptions.repository.models import Beerds
@mapper_registry.mapped
@ -19,6 +22,12 @@ class Results(UJsonMixin):
__tablename__ = "recognizer_results"
__table_args__ = (ForeignKeyConstraint(["attachment_id"], ["attachments.id"], "votes_attachment_id_fk"),)
__mapper_args__ = {
"properties": {
"attachment": relationship(Attachment, foreign_keys="Results.attachment_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
attachment_id: str = field(metadata={"sa": Column(String(), nullable=False)})
user_id: str = field(metadata={"sa": Column(String(), nullable=False)})
@ -28,6 +37,10 @@ class Results(UJsonMixin):
metadata={"sa": Column(DateTime(timezone=True), nullable=False)},
)
def __str__(self):
formatted_date = self.created_at.strftime("%Y-%m-%d %H:%M")
return f"{formatted_date}, device_id: {self.device_id}, user_id: {self.user_id}"
@mapper_registry.mapped
@dataclass
@ -39,6 +52,13 @@ class ResultBeerds(UJsonMixin):
ForeignKeyConstraint(["beerd_id"], ["beerds.id"], "recognizer_results_beerd_id_fk"),
)
__mapper_args__ = {
"properties": {
"result": relationship(Results, foreign_keys="ResultBeerds.recognizer_results_id"),
"beerd": relationship(Beerds, foreign_keys="ResultBeerds.beerd_id"),
}
}
id: str = field(metadata={"sa": Column(String(), primary_key=True, nullable=False)})
recognizer_results_id: str = field(metadata={"sa": Column(String(), nullable=False)})
beerd_id: str = field(metadata={"sa": Column(String(), nullable=False)})

View File

@ -41,7 +41,7 @@ async function SavePhoto(self) {
for (let key in json.results) {
currentBeerdName.push(json.results[key]);
if (json.description != undefined) {
text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%) <br/><a href="${json.description[json.results[key]]}" target='_blank'>Описание </a></div>`;
text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%) <br/><a href="${json.description[json.results[key]]}" target='_blank'>Описание и фото</a></div>`;
} else {
text += `<div class='image-block'><div class='image-text'>${json.results[key]} (вероятность: ${Math.round(parseFloat(key) * 100)}%)</div>`;
}

View File

@ -45,6 +45,6 @@
{% block form %}{% endblock %}
</body>
</section>
<script src="/static/scripts.js?v=7"></script>
<script src="/static/scripts.js?v=8"></script>
</html>