Skip to content

Commit

Permalink
Merge pull request #3 from greyli/refactor
Browse files Browse the repository at this point in the history
Refactor database models and set up CI
  • Loading branch information
greyli authored Aug 10, 2024
2 parents 00a8318 + 42a4ded commit 8d4cd22
Show file tree
Hide file tree
Showing 40 changed files with 1,277 additions and 596 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Tests
on:
push:
branches:
- main
paths-ignore:
- '*.md'
pull_request:
branches:
- main
paths-ignore:
- '*.md'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Test with pytest
run: |
pytest -v
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ $ pdm install
Generate fake data then run:

```
$ pdm run flask fake
$ pdm run flask lorem
$ pdm run flask run
* Running on http://127.0.0.1:5000/
```
Expand Down
2 changes: 2 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os

from dotenv import load_dotenv

dotenv_path = os.path.join(os.path.dirname(__file__), '.env')
if os.path.exists(dotenv_path):
load_dotenv(dotenv_path)
Expand Down
30 changes: 16 additions & 14 deletions moments/__init__.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import os

import click
from flask import Flask, render_template
from flask_login import current_user
from flask_wtf.csrf import CSRFError
from flask import Flask

from moments.blueprints.admin import admin_bp
from moments.blueprints.ajax import ajax_bp
from moments.blueprints.auth import auth_bp
from moments.blueprints.main import main_bp
from moments.blueprints.user import user_bp
from moments.core.extensions import bootstrap, db, login_manager, mail, dropzone, whooshee, avatars, csrf
from moments.models import User, Photo, Tag, Follow, Notification, Comment, Collect
from moments.settings import config
from moments.core.commands import register_commands
from moments.core.errors import register_error_handlers
from moments.core.extensions import avatars, bootstrap, csrf, db, dropzone, login_manager, mail, whooshee
from moments.core.logging import register_logging
from moments.core.templating import register_template_handlers
from moments.core.request import register_request_handlers
from moments.core.errors import register_error_handlers
from moments.core.templating import register_template_handlers
from moments.models import Collection, Comment, Follow, Notification, Photo, Tag, User
from moments.settings import config


def create_app(config_name):
Expand Down Expand Up @@ -48,8 +43,15 @@ def create_app(config_name):

@app.shell_context_processor
def make_shell_context():
return dict(db=db, User=User, Photo=Photo, Tag=Tag,
Follow=Follow, Collect=Collect, Comment=Comment,
Notification=Notification)
return dict(
db=db,
User=User,
Photo=Photo,
Tag=Tag,
Follow=Follow,
Collect=Collection,
Comment=Comment,
Notification=Notification,
)

return app
61 changes: 24 additions & 37 deletions moments/blueprints/admin.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from flask import render_template, flash, Blueprint, request, current_app
from flask import Blueprint, current_app, flash, render_template, request
from flask_login import login_required
from sqlalchemy import select, func
from sqlalchemy import func, select

from moments.decorators import admin_required, permission_required
from moments.core.extensions import db
from moments.decorators import admin_required, permission_required
from moments.forms.admin import EditProfileAdminForm
from moments.models import Role, User, Tag, Photo, Comment
from moments.models import Comment, Photo, Role, Tag, User
from moments.utils import redirect_back

admin_bp = Blueprint('admin', __name__)
Expand All @@ -15,34 +15,25 @@
@login_required
@permission_required('MODERATE')
def index():
user_count = db.session.scalar(
select(func.count(User.id))
)
locked_user_count = db.session.scalar(
select(func.count(User.id)).filter_by(locked=True)
)
blocked_user_count = db.session.scalar(
select(func.count(User.id)).filter_by(active=False)
)
photo_count = db.session.scalar(
select(func.count(Photo.id))
)
reported_photos_count = db.session.scalar(
select(func.count(Photo.id)).filter(Photo.flag > 0)
)
tag_count = db.session.scalar(
select(func.count(Tag.id))
)
comment_count = db.session.scalar(
select(func.count(Comment.id))
)
reported_comments_count = db.session.scalar(
select(func.count(Comment.id)).filter(Comment.flag > 0)
user_count = db.session.scalar(select(func.count(User.id)))
locked_user_count = db.session.scalar(select(func.count(User.id)).filter_by(locked=True))
blocked_user_count = db.session.scalar(select(func.count(User.id)).filter_by(active=False))
photo_count = db.session.scalar(select(func.count(Photo.id)))
reported_photos_count = db.session.scalar(select(func.count(Photo.id)).filter(Photo.flag > 0))
tag_count = db.session.scalar(select(func.count(Tag.id)))
comment_count = db.session.scalar(select(func.count(Comment.id)))
reported_comments_count = db.session.scalar(select(func.count(Comment.id)).filter(Comment.flag > 0))
return render_template(
'admin/index.html',
user_count=user_count,
photo_count=photo_count,
tag_count=tag_count,
comment_count=comment_count,
locked_user_count=locked_user_count,
blocked_user_count=blocked_user_count,
reported_comments_count=reported_comments_count,
reported_photos_count=reported_photos_count,
)
return render_template('admin/index.html', user_count=user_count, photo_count=photo_count,
tag_count=tag_count, comment_count=comment_count, locked_user_count=locked_user_count,
blocked_user_count=blocked_user_count, reported_comments_count=reported_comments_count,
reported_photos_count=reported_photos_count)


@admin_bp.route('/profile/<int:user_id>', methods=['GET', 'POST'])
Expand Down Expand Up @@ -199,13 +190,9 @@ def manage_comment(order):
per_page = current_app.config['MOMENTS_MANAGE_COMMENT_PER_PAGE']
order_rule = 'flag'
if order == 'by_time':
pagination = db.paginate(
select(Comment).order_by(Comment.created_at.desc()
), page=page, per_page=per_page)
pagination = db.paginate(select(Comment).order_by(Comment.created_at.desc()), page=page, per_page=per_page)
order_rule = 'time'
else:
pagination = db.paginate(
select(Comment).order_by(Comment.flag.desc()
), page=page, per_page=per_page)
pagination = db.paginate(select(Comment).order_by(Comment.flag.desc()), page=page, per_page=per_page)
comments = pagination.items
return render_template('admin/manage_comment.html', pagination=pagination, comments=comments, order_rule=order_rule)
12 changes: 5 additions & 7 deletions moments/blueprints/ajax.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from flask import render_template, Blueprint
from flask import Blueprint, render_template
from flask_login import current_user
from sqlalchemy import select, func
from sqlalchemy import func, select

from moments.models import User, Photo, Notification, Collect, Follow
from moments.core.extensions import db
from moments.models import Notification, Photo, User
from moments.notifications import push_collect_notification, push_follow_notification

ajax_bp = Blueprint('ajax', __name__)
Expand All @@ -14,9 +14,7 @@ def notifications_count():
if not current_user.is_authenticated:
return {'message': 'Login required.'}, 403

count = db.session.scalar(
select(func.count(Notification.id)).filter_by(receiver_id=current_user.id, is_read=False)
)
count = db.session.scalar(select(func.count(Notification.id)).filter_by(receiver_id=current_user.id, is_read=False))
return {'count': count}


Expand Down Expand Up @@ -53,7 +51,7 @@ def collect(photo_id):

current_user.collect(photo)
if current_user != photo.author and photo.author.receive_collect_notification:
push_collect_notification(collector=current_user, photo_id=photo_id, receiver=photo.author)
push_collect_notification(user=current_user, photo_id=photo_id, receiver=photo.author)
return {'message': 'Photo collected.'}


Expand Down
27 changes: 12 additions & 15 deletions moments/blueprints/auth.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from flask import render_template, flash, redirect, url_for, Blueprint
from flask_login import login_user, logout_user, login_required, current_user, login_fresh, confirm_login
from sqlalchemy import select, func
from flask import Blueprint, flash, redirect, render_template, url_for
from flask_login import confirm_login, current_user, login_fresh, login_required, login_user, logout_user
from sqlalchemy import select

from moments.emails import send_confirmation_email, send_reset_password_email
from moments.core.extensions import db
from moments.forms.auth import LoginForm, RegisterForm, ForgetPasswordForm, ResetPasswordForm
from moments.emails import send_confirmation_email, send_reset_password_email
from moments.forms.auth import ForgetPasswordForm, LoginForm, RegisterForm, ResetPasswordForm
from moments.models import User
from moments.settings import Operations
from moments.utils import generate_token, parse_token, redirect_back
Expand All @@ -19,9 +19,8 @@ def login():

form = LoginForm()
if form.validate_on_submit():
user = db.session.scalar(
select(User).filter(func.lower(User.email) == form.email.data.lower())
)
stmt = select(User).filter_by(email=form.email.data.lower())
user = db.session.scalar(stmt)
if user is not None and user.validate_password(form.password.data):
if login_user(user, form.remember_me.data):
flash('Login success.', 'info')
Expand Down Expand Up @@ -69,7 +68,7 @@ def register():
user = User(name=name, email=email, username=username, password=password)
db.session.add(user)
db.session.commit()
token = generate_token(user=user, operation='confirm')
token = generate_token(user=user, operation=Operations.CONFIRM)
send_confirmation_email(user=user, token=token)
flash('Confirm email sent, check your inbox.', 'info')
return redirect(url_for('.login'))
Expand Down Expand Up @@ -111,9 +110,8 @@ def forget_password():

form = ForgetPasswordForm()
if form.validate_on_submit():
user = db.session.scalar(
select(User).filter(func.lower(User.email) == form.email.data.lower())
)
stmt = select(User).filter_by(email=form.email.data.lower())
user = db.session.scalar(stmt)
if user:
token = generate_token(user=user, operation=Operations.RESET_PASSWORD)
send_reset_password_email(user=user, token=token)
Expand All @@ -131,9 +129,8 @@ def reset_password(token):

form = ResetPasswordForm()
if form.validate_on_submit():
user = db.session.scalar(
select(User).filter(func.lower(User.email) == form.email.data.lower())
)
stmt = select(User).filter_by(email=form.email.data.lower())
user = db.session.scalar(stmt)
if user is None:
return redirect(url_for('main.index'))
if parse_token(user=user, token=token, operation=Operations.RESET_PASSWORD):
Expand Down
Loading

0 comments on commit 8d4cd22

Please sign in to comment.