diff --git a/requirements.txt b/requirements.txt index 7686adb..d0fca8b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,3 +16,5 @@ SQLAlchemy==2.0.32 typing_extensions==4.12.2 Werkzeug==3.0.3 WTForms==3.1.2 +Flask-CKEditor==1.0.0 +Flask-WTF==1.2.1 diff --git a/src/__init__.py b/src/__init__.py index 98d7ce2..fdc5b6e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -2,13 +2,13 @@ from flask_admin.contrib.sqla import ModelView from src.config import Config -from src.extensions import db, migrate, login_manager +from src.extensions import db, migrate, login_manager, ckeditor from src.views import main_blueprint from src.admin import admin -from src.admin.term import TermView, ConnectedTermView +from src.admin.term import TermView, CategoryView from src.admin.user import UserView from src.commands import init_db, populate_db -from src.models import User, Term, ConnectedTerm +from src.models import User, Term, Category COMMANDS = [ @@ -19,6 +19,8 @@ def create_app(): app = Flask(__name__, template_folder="templates") app.config.from_object(Config) + app.config['CKEDITOR_PKG_TYPE'] = 'basic' + register_extensions(app) app.register_blueprint(main_blueprint) @@ -39,6 +41,9 @@ def register_extensions(app): # Login-Manager login_manager.init_app(app) + # CKEditor + ckeditor.init_app(app) + @login_manager.user_loader def load_user(user_id): return User.query.get(user_id) @@ -46,7 +51,7 @@ def load_user(user_id): # Flask-Admin admin.init_app(app) admin.add_view(TermView(Term, db.session, endpoint="term_panel", name="Terms")) - admin.add_view(ConnectedTermView(ConnectedTerm, db.session, endpoint="connected_term", name="Connected terms")) + admin.add_view(CategoryView(Category, db.session, endpoint="category", name="categories")) admin.add_view(UserView(User, db.session)) diff --git a/src/admin/term.py b/src/admin/term.py index 561158e..7f50840 100644 --- a/src/admin/term.py +++ b/src/admin/term.py @@ -1,28 +1,46 @@ from src.admin.base import SecureModelView -from src.models import Category +from src.models import ConnectedTerm +from flask_ckeditor import CKEditorField +from flask_admin.form.widgets import Select2Widget -class ConnectedTermView(SecureModelView): +class CategoryView(SecureModelView): can_view_details = True + edit_modal = True + create_modal = True + can_create = True + can_edit = True + can_export = True - # Exclude the relationship fields - column_exclude_list = ['term1', 'term2'] - # Display foreign keys instead - column_list = ['term1_id', 'term2_id', 'is_synonym'] + + form_columns = ['name', 'parent'] + column_list = ['name', 'parent'] + + column_labels = { + "name": "კატეგორია", + "parent": "მშობელი კატეგორია", + } class TermView(SecureModelView): can_view_details = True - edit_modal = True - create_modal = True can_create = True can_edit = True can_export = True - inline_models = (Category,) + + form_overrides = { + 'context_source': CKEditorField, + 'term_source': CKEditorField, + 'definition_source': CKEditorField, + + } + create_template = 'admin/edit.html' + edit_template = 'admin/edit.html' + column_filters = ["geo_word", "eng_word"] @@ -38,7 +56,9 @@ class TermView(SecureModelView): "context", "context_source", "comment", - "category" + "category", + "synonyms", + "connected_terms" ] form_columns = [ @@ -52,10 +72,11 @@ class TermView(SecureModelView): "context", "context_source", "comment", - "category" + "category", + "synonyms", + "connected_terms" ] - column_sortable_list = [ "geo_word", "eng_word" @@ -78,4 +99,45 @@ class TermView(SecureModelView): "context_source": "კონტექსტის წყარო", "comment": "კომენტარი", "category": "კატეგორია", - } \ No newline at end of file + "synonyms": "სინონიმები", + "connected_terms": "დაკავშირებული სიტყვები" + } + + + form_args = { + 'synonyms': { + 'widget': Select2Widget(multiple=True) + }, + 'connected_terms': { + 'widget': Select2Widget(multiple=True) + } + } + + + def on_model_change(self, form, model, is_created): + + # Add synonyms + if form.synonyms.data: + for synonym_id in form.synonyms.data: + if synonym_id != model.id: + ConnectedTerm(term1_id=model.id, term2_id=synonym_id, is_synonym=True).save() + + # Add connected terms + if form.connected_terms.data: + for connected_id in form.connected_terms.data: + if connected_id != model.id: + ConnectedTerm(term1_id=model.id, term2_id=connected_id, is_synonym=False).save() + + super().on_model_change(form, model, is_created) + + + def on_model_delete(self, model): + # Manually delete connections (ConnectedTerm records) referencing the term + ConnectedTerm.query.filter( + (ConnectedTerm.term1_id == model.id) | (ConnectedTerm.term2_id == model.id) + ).delete(synchronize_session=False) + + # Proceed with the actual term deletion + super().on_model_delete(model) + + diff --git a/src/database.db b/src/database.db index f314715..3e057ae 100644 Binary files a/src/database.db and b/src/database.db differ diff --git a/src/extensions.py b/src/extensions.py index e7c1338..05f1063 100644 --- a/src/extensions.py +++ b/src/extensions.py @@ -1,8 +1,10 @@ from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager +from flask_ckeditor import CKEditor db = SQLAlchemy() migrate = Migrate() -login_manager = LoginManager() \ No newline at end of file +login_manager = LoginManager() +ckeditor = CKEditor() \ No newline at end of file diff --git a/src/models/base.py b/src/models/base.py index f5362fb..8c4c66d 100644 --- a/src/models/base.py +++ b/src/models/base.py @@ -20,5 +20,5 @@ def save(self): def delete(self): - db.session.remove(self) + db.session.delete(self) db.session.commit() \ No newline at end of file diff --git a/src/models/terms.py b/src/models/terms.py index 964fb11..a4ecee5 100644 --- a/src/models/terms.py +++ b/src/models/terms.py @@ -10,19 +10,39 @@ class Term(BaseModel): geo_word = db.Column(db.String(100), nullable=False) eng_word = db.Column(db.String(100), nullable=False) grammar_form = db.Column(db.String(50), nullable=True) - term_source = db.Column(db.String(100), nullable=False) + term_source = db.Column(db.Text, nullable=False) definition = db.Column(db.Text, nullable=False) - definition_source = db.Column(db.String(100), nullable=False) + definition_source = db.Column(db.Text, nullable=False) term_type = db.Column(db.String(50), nullable=True) context = db.Column(db.Text, nullable=True) - context_source = db.Column(db.String(100), nullable=True) + context_source = db.Column(db.Text, nullable=True) comment = db.Column(db.Text, nullable=True) category = db.relationship("Category", secondary="terms_categories", backref="terms") + # Relationships for synonyms + synonyms = db.relationship( + "Term", + secondary="connected_terms", + primaryjoin="and_(Term.id == ConnectedTerm.term1_id, ConnectedTerm.is_synonym == True)", + secondaryjoin="and_(Term.id == ConnectedTerm.term2_id, ConnectedTerm.is_synonym == True)", + backref="synonym_for" + ) + + # Relationships for general connected terms + connected_terms = db.relationship( + "Term", + secondary="connected_terms", + primaryjoin="and_(Term.id == ConnectedTerm.term1_id, ConnectedTerm.is_synonym == False)", + secondaryjoin="and_(Term.id == ConnectedTerm.term2_id, ConnectedTerm.is_synonym == False)", + backref="connected_for" + ) + + def __repr__(self): return f"({self.eng_word} - {self.geo_word})" + @@ -32,14 +52,15 @@ class ConnectedTerm(BaseModel): id = db.Column(db.Integer, primary_key=True) term1_id = db.Column(db.Integer, db.ForeignKey('terms.id'), nullable=True) term2_id = db.Column(db.Integer, db.ForeignKey('terms.id'), nullable=True) - is_synonym = db.Column(db.Boolean, nullable=False) + is_synonym = db.Column(db.Boolean, nullable=False, default=False) + term1 = db.relationship('Term', foreign_keys=[term1_id], backref='term1_connections') term2 = db.relationship('Term', foreign_keys=[term2_id], backref='term2_connections') def __repr__(self): - return f"ConnectedTerm('{self.term1_id}', '{self.term2_id}', synonym={self.is_synonym})" + return f"{self.term1} - {self.term2}" diff --git a/src/templates/admin/base.html b/src/templates/admin/base.html index 4e9af40..4459d46 100644 --- a/src/templates/admin/base.html +++ b/src/templates/admin/base.html @@ -34,10 +34,10 @@ {% endblock %} {% block head_tail %} {% endblock %} + {{ ckeditor.load() }}
{% block page_body %} -