diff --git a/myapp/__init__.py b/myapp/__init__.py index 666fbbc..35db1ac 100644 --- a/myapp/__init__.py +++ b/myapp/__init__.py @@ -48,6 +48,9 @@ from . import ns_api # Авторизация from . import ns_login +# Заметки +from . import ns_note + # Статьи from . import ns_page diff --git a/myapp/models/__init__.py b/myapp/models/__init__.py index e72746c..444d2af 100644 --- a/myapp/models/__init__.py +++ b/myapp/models/__init__.py @@ -11,7 +11,10 @@ from sqlalchemy_utils import database_exists, create_database from .. import app -engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], echo=True) +engine = create_engine( + app.config['SQLALCHEMY_DATABASE_URI'], + echo=app.config['SQLDEBUG'] +) if not database_exists(engine.url): create_database(engine.url) @@ -30,6 +33,9 @@ from .tag import Tag # Статьи from .page import Page, TagPage +# Заметки +from .note import Note, TagNote + Base.metadata.create_all(engine) __all__ = [] diff --git a/myapp/models/note.py b/myapp/models/note.py new file mode 100644 index 0000000..b495dca --- /dev/null +++ b/myapp/models/note.py @@ -0,0 +1,73 @@ +__author__ = 'RemiZOffAlex' +__copyright__ = '(c) RemiZOffAlex' +__license__ = 'MIT' +__email__ = 'remizoffalex@mail.ru' +__url__ = 'http://remizoffalex.ru' + +import datetime +from sqlalchemy import Column, Boolean, Integer, ForeignKey, String, DateTime +from sqlalchemy.orm import relationship + +from . import Base + + +class Note(Base): + """Заметки + """ + __tablename__ = "note" + + id = Column(Integer, primary_key=True) + user_id = Column(Integer, ForeignKey('user.id')) + title = Column(String) + body = Column(String, default='') + created = Column(DateTime) # Дата создания + updated = Column(DateTime) # Дата обновления + + # Связи + user = relationship( + "User", + primaryjoin="Note.user_id==User.id", + uselist=False + ) + tags = relationship("TagNote", primaryjoin="Note.id==TagNote.note_id") + + + def __init__(self, user, title): + assert type(user).__name__=='User', app.logger.info('Не передан объект User') + self.user_id = user.id + self.title = title + self.created = datetime.datetime.now() + self.updated = datetime.datetime.now() + + def __repr__(self): + return "".format(self.id, self.title) + + def as_dict(self): + return {c.name: getattr(self, c.name) for c in self.__table__.columns} + + +class TagNote(Base): + """Теги к заметкам""" + __tablename__ = "tagnote" + + id = Column(Integer, primary_key=True) + note_id = Column(Integer, ForeignKey('note.id')) + tag_id = Column(Integer, ForeignKey('tag.id')) + created = Column(DateTime) # Дата создания + + # Связи + note = relationship("Note", primaryjoin="TagNote.note_id==Note.id", uselist=False) + tag = relationship("Tag", primaryjoin="TagNote.tag_id==Tag.id", uselist=False) + + def __init__(self, note, tag): + assert type(note).__name__=='Note', app.logger.info('Не передан объект Note') + assert type(tag).__name__=='Tag', app.logger.info('Не передан объект Tag') + self.note_id = note.id + self.tag_id = tag.id + self.created = datetime.datetime.now() + + def __repr__(self): + return "" % (self.id) + + def as_dict(self): + return {c.name: getattr(self, c.name) for c in self.__table__.columns} diff --git a/myapp/ns_api/__init__.py b/myapp/ns_api/__init__.py index 973e8fc..7bfd0ef 100644 --- a/myapp/ns_api/__init__.py +++ b/myapp/ns_api/__init__.py @@ -33,6 +33,7 @@ jsonrpc = JSONRPC(app, '/api') from . import ( login, + note, page, tag, user diff --git a/myapp/ns_api/note.py b/myapp/ns_api/note.py new file mode 100644 index 0000000..63e67f3 --- /dev/null +++ b/myapp/ns_api/note.py @@ -0,0 +1,127 @@ +__author__ = 'RemiZOffAlex' +__email__ = 'remizoffalex@mail.ru' +__url__ = 'https://remizoffalex.ru' + +from . import jsonrpc, login_required +from .. import app, lib, models + + +@jsonrpc.method('note(id=int)') +def note_id(id): + """Заметка + """ + note = models.db_session.query( + models.Note + ).filter( + models.Note.id==id + ).first() + if note is None: + raise ValueError + + result = note.as_dict() + result['user'] = note.user.as_dict() + result['tags'] = [] + for tagLink in note.tags: + result['tags'].append(tagLink.tag.as_dict()) + return result + + +@jsonrpc.method('note.update(title=str, body=str)') +@login_required +def note_update(title, body): + """Обновить заметку + """ + note = models.db_session.query( + models.Note + ).filter( + models.Note.id==id + ).first() + if note is None: + raise ValueError + + note.title = title + note.body = body + + result = note.as_dict() + result['user'] = note.user.as_dict() + result['tags'] = [] + for tagLink in note.tags: + result['tags'].append(tagLink.tag.as_dict()) + return result + + +@jsonrpc.method('note.add(title=str, body=str)') +@login_required +def note_add(title, body): + """Добавление новой заметки + """ + newNote = models.Note( + lib.get_user(), + title + ) + newNote.body = body + models.db_session.add(newNote) + models.db_session.commit() + + result = newNote.as_dict() + result['user'] = newNote.user.as_dict() + result['tags'] = [] + return result + + +@jsonrpc.method('note.destroy(id=int)') +@login_required +def note_destroy(id): + """Полное уничтожение заметки + + Аргументы: + id -- ID заметки + """ + note = models.db_session.query( + models.Note + ).filter( + models.Note.id==id + ).first() + if note is None: + raise ValueError + + models.db_session.delete(note) + models.db_session.commit() + + return 'ok' + + +@jsonrpc.method('notes(page=int)') +def notes_list(page): + """Список заметок + """ + notes = models.db_session.query( + models.Note + ).order_by( + models.Note.title.asc() + ) + notes = lib.getpage( + notes, + page, + app.config['ITEMS_ON_PAGE'] + ).all() + + result = [] + for note in notes: + newRow = note.as_dict() + newRow['user'] = note.user.as_dict() + newRow['tags'] = [] + for tagLink in note.tags: + newRow['tags'].append(tagLink.tag.as_dict()) + result.append(newRow) + return result + + +@jsonrpc.method('notes.count') +def notes_count(): + """Количество заметок + """ + result = models.db_session.query( + models.Note + ).count() + return result diff --git a/myapp/ns_api/tag.py b/myapp/ns_api/tag.py index 2e7c2d9..cc3a379 100644 --- a/myapp/ns_api/tag.py +++ b/myapp/ns_api/tag.py @@ -132,6 +132,73 @@ def tag_pages_count(id): return result +@jsonrpc.method('tag.notes(id=int, page=int)') +@login_required +def tag_notes_list(id, page): + """Список заметок + """ + tag = models.db_session.query( + models.Tag + ).filter( + models.Tag.id==id + ).first() + if tag is None: + raise ValueError + indexes = models.db_session.query( + models.TagNote.note_id + ).filter( + models.TagNote.tag_id==id + ) + notes = models.db_session.query( + models.Note + ).filter( + models.Note.user_id==lib.get_user().id, + models.Note.id.in_(indexes) + ).order_by( + models.Note.title.asc() + ) + notes = lib.getpage( + notes, + page, + app.config['ITEMS_ON_PAGE'] + ).all() + + result = [] + for note in notes: + newRow = note.as_dict() + newRow['tags'] = [] + for tagLink in note.tags: + newRow['tags'].append(tagLink.tag.as_dict()) + result.append(newRow) + return result + + +@jsonrpc.method('tag.notes.count(id=int)') +@login_required +def tag_notes_count(id): + """Общее количество заметок + """ + tag = models.db_session.query( + models.Tag + ).filter( + models.Tag.id==id + ).first() + if tag is None: + raise ValueError + indexes = models.db_session.query( + models.TagNote.note_id + ).filter( + models.TagNote.tag_id==id + ) + result = models.db_session.query( + models.Note + ).filter( + models.Note.user_id==lib.get_user().id, + models.Note.id.in_(indexes) + ).count() + return result + + @jsonrpc.method('tags()') def tags_list(): """ @@ -205,6 +272,79 @@ def tag_deleteFromPage(tag, id): return 'Тег {} удален'.format(id) +@jsonrpc.method('tag.addToNote(tag=int, id=int)') +@login_required +def tag_addToNote(tag, id): + """ + Добавление тега в заметку + """ + noteRow = models.db_session.query( + models.Note + ).filter( + models.Note.id==id, + models.Note.user_id==lib.get_user().id + ).first() + if noteRow is None: + raise ValueError + tagRow = models.db_session.query( + models.Tag + ).filter( + models.Tag.id==tag + ).first() + if tagRow is None: + raise ValueError + exist = models.db_session.query( + models.TagNote + ).filter( + models.TagNote.tag_id==tagRow.id, + models.TagNote.note_id==noteRow.id + ).first() + if exist: + raise ValueError + newtagNote = models.TagNote( + noteRow, + tagRow + ) + models.db_session.add(newtagNote) + models.db_session.commit() + result = tagRow.as_dict() + return result + + +@jsonrpc.method('tag.deleteFromNote(tag=int, id=int)') +@login_required +def tag_deleteFromNote(tag, id): + """ + Удаление тега из заметки + """ + noteRow = models.db_session.query( + models.Note + ).filter( + models.Note.id==id, + models.Note.user_id==lib.get_user().id + ).first() + if noteRow is None: + raise ValueError + tagRow = models.db_session.query( + models.Tag + ).filter( + models.Tag.id==tag + ).first() + if tagRow is None: + raise ValueError + exist = models.db_session.query( + models.TagNote + ).filter( + models.TagNote.tag_id==tag, + models.TagNote.note_id==id + ).first() + if exist is None: + raise ValueError + models.db_session.delete(exist) + models.db_session.commit() + return 'ok' + + @jsonrpc.method('tags.groups') def tags_groups(): """ diff --git a/myapp/ns_note/__init__.py b/myapp/ns_note/__init__.py new file mode 100644 index 0000000..98efb65 --- /dev/null +++ b/myapp/ns_note/__init__.py @@ -0,0 +1,18 @@ +__author__ = 'RemiZOffAlex' +__copyright__ = '(c) RemiZOffAlex' +__license__ = 'MIT' +__email__ = 'remizoffalex@mail.ru' +__url__ = 'https://remizoffalex.ru' + +import os +import jinja2 + +from . import views +from .. import app + + +my_loader = jinja2.ChoiceLoader([ + app.jinja_loader, + jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)) + "/templates"), +]) +app.jinja_loader = my_loader diff --git a/myapp/ns_note/templates/note.html b/myapp/ns_note/templates/note.html new file mode 100644 index 0000000..29f2e56 --- /dev/null +++ b/myapp/ns_note/templates/note.html @@ -0,0 +1,69 @@ +{% extends "user/skeleton.html" %} +{% block content %} +{% raw %} + +

+ +{{ note.title }} +

+ + + + + + + +{% endraw %} +{% endblock %} + +{% block breadcrumb %} +{% raw %} + +{% endraw %} +{% endblock %} + +{% block script %} + + + + + +{% endblock %} diff --git a/myapp/ns_note/templates/note_add.html b/myapp/ns_note/templates/note_add.html new file mode 100644 index 0000000..5002bb1 --- /dev/null +++ b/myapp/ns_note/templates/note_add.html @@ -0,0 +1,82 @@ +{% extends "user/skeleton.html" %} +{% block content %} + + +

+ +Новая заметка +

+
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ +{% endblock %} + +{% block breadcrumb %} +{% raw %} + +{% endraw %} +{% endblock %} + +{% block script %} +{% import 'inc/editor.js' as editor %} +{{ editor.plugin('tinymce') }} + + +{% endblock %} diff --git a/myapp/ns_note/templates/note_edit.html b/myapp/ns_note/templates/note_edit.html new file mode 100644 index 0000000..756b89b --- /dev/null +++ b/myapp/ns_note/templates/note_edit.html @@ -0,0 +1,81 @@ +{% extends "user/skeleton.html" %} +{% block content %} + +

+ +Редактирование заметки +

+
+ +
+ + +
+ +
+ + +
+ +
+
+ +
+
+ + +{% endblock %} + +{% block breadcrumb %} +{% raw %} + +{% endraw %} +{% endblock %} + +{% block script %} +{% import 'inc/editor.js' as editor %} +{{ editor.plugin('tinymce') }} + + +{% endblock %} diff --git a/myapp/ns_note/templates/notes.html b/myapp/ns_note/templates/notes.html new file mode 100644 index 0000000..95b2ce0 --- /dev/null +++ b/myapp/ns_note/templates/notes.html @@ -0,0 +1,157 @@ +{% extends "user/skeleton.html" %} +{% block content %} + +

+
+ +
+ + +Заметки +

+
+ +{% include 'inc/filter.html' %} + +{% raw %} + + +
+
+ + + +
+
+ + {{ tag.name }}  + +
+
+ +
+
+Создано: {{ note.created }}  +Обновлено: {{ note.updated }} +
+
+ +
+
+ + + + + +{% endraw %} +{% endblock %} + +{% block script %} + + + + + +{% endblock %} diff --git a/myapp/ns_note/views.py b/myapp/ns_note/views.py new file mode 100644 index 0000000..69fd4cd --- /dev/null +++ b/myapp/ns_note/views.py @@ -0,0 +1,60 @@ +__author__ = 'RemiZOffAlex' +__copyright__ = '(c) RemiZOffAlex' +__license__ = 'MIT' +__email__ = 'remizoffalex@mail.ru' +__url__ = 'https://remizoffalex.ru' + +from flask import render_template, escape, request, session, redirect + +from .. import app, lib, models + + +@app.route('/note/') +def note_id(id): + """Заметка""" + note = models.db_session.query( + models.Note + ).filter( + models.Note.id==id + ).first() + if note is None: + abort(404) + + pagedata = {} + pagedata['title'] = '{} - {}'.format(note.title, app.config['TITLE']) + + pagedata['note'] = note.as_dict() + pagedata['note']['user'] = note.user.as_dict() + pagedata['note']['tags'] = [] + for tagLink in note.tags: + pagedata['note']['tags'].append(tagLink.tag.as_dict()) + + body = render_template('note.html', pagedata=pagedata) + return body + + +@app.route('/note/add') +def note_add(): + """Добавление новой заметки + """ + pagedata = {} + pagedata['title'] = 'Новая заметка - ' + app.config['TITLE'] + body = render_template('note_add.html', pagedata=pagedata) + return body + + +@app.route('/notes', defaults={'page': 1}) +@app.route('/notes/') +def notes_list(page): + """Список заметок + """ + pagedata = {} + + pagedata['pagination'] = { + "page": page, + "per_page": app.config['ITEMS_ON_PAGE'], + "size": 0 + } + + body = render_template('notes.html', pagedata=pagedata) + return body