Artberry-web/app.py
2025-04-20 23:35:38 +03:00

973 lines
36 KiB
Python

import os
import io
import re
import uuid
import shutil
import random
import asyncio
from datetime import datetime
import requests
from authlib.integrations.flask_client import OAuth
from auth import auth_bp, init_oauth
from config import Config, configure_oauth
from flask_session import Session
from PIL import Image as PILImage
from sqlalchemy.exc import IntegrityError
from werkzeug.exceptions import BadRequest
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename
from flask import Flask, abort, render_template, redirect, url_for, request, session, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_wtf import FlaskForm, RecaptchaField, CSRFProtect
from flask_wtf.file import FileAllowed
from flask_wtf.csrf import validate_csrf
from wtforms import StringField, PasswordField, SubmitField, FileField, BooleanField, RadioField, SelectField, TextAreaField
from wtforms.validators import DataRequired, Length, EqualTo, ValidationError, Regexp
from dotenv import load_dotenv, find_dotenv
import aiofiles.os
from sqlalchemy import func, or_
import magic
from config import Config
from models import db, bcrypt, User, Comments, Image, Votes, VideoVotes, Video, Comic, ComicPage, ComicVotes, Cookies, Views, Item, UserItem, Post, Subscription, EditTagsForm, EditVideoForm, RegistrationForm, LoginForm, EmptyForm
from admin import register_admin_routes
from upload import upload_bp
from utils import allowed_file, check_file_content, check_file_size, convert_to_webp, generate_unique_filename, get_content_query, get_client_ip, get_autocomplete_suggestions
from auth import auth_bp
app = Flask(__name__)
csrf = CSRFProtect(app)
app.config.from_object(Config)
oauth = configure_oauth(app)
init_oauth(oauth)
db.init_app(app)
bcrypt.init_app(app)
login_manager = LoginManager(app)
login_manager.login_view = 'auth.login'
@login_manager.user_loader
def load_user(user_id):
return db.session.get(User, int(user_id))
from flask_session import Session
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './flask_session'
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SECRET_KEY'] = Config.SECRET_KEY
Session(app)
register_admin_routes(app)
app.register_blueprint(upload_bp)
app.register_blueprint(auth_bp)
@app.route('/')
def index():
page = request.args.get('page', 1, type=int)
search_query = request.args.get('search')
subscriptions = []
if current_user.is_authenticated:
subscriptions = [
sub.author.username
for sub in Subscription.query.filter_by(user_id=current_user.id).all()
]
query = get_content_query(Image, subscriptions, search_query)
pagination = query.paginate(page=page, per_page=25, error_out=False)
user_cookies = 0
if current_user.is_authenticated:
user_cookies_record = Cookies.query.filter_by(username=current_user.username).first()
user_cookies = user_cookies_record.cookies if user_cookies_record else 0
return render_template(
'index.html',
images=pagination.items,
pagination=pagination,
user_cookies=user_cookies,
search_query=search_query,
content_type='art'
)
@app.route('/arts')
def arts():
return render_template(
'arts.html'
)
@app.route('/catalogue/arts')
def arts_catalogue():
return render_template(
'arts-catalogue.html'
)
@app.route('/vote_art/<int:image_id>', methods=['POST'])
@login_required
def vote_art(image_id):
image = Image.query.get_or_404(image_id)
user_cookies = Cookies.query.filter_by(username=current_user.username).first()
if image.username == current_user.username:
return redirect(url_for('view', content_type='art', id=image_id))
if user_cookies and user_cookies.cookies > 0:
existing_vote = Votes.query.filter_by(username=current_user.username, image_id=image_id).first()
if not existing_vote:
user_cookies.cookies -= 1
image.cookie_votes += 1
new_vote = Votes(username=current_user.username, image_id=image.id)
db.session.add(new_vote)
db.session.commit()
return redirect(url_for('view', content_type='art', id=image_id))
@app.route('/view/<content_type>/<int:id>', methods=['GET', 'POST'])
def view(content_type, id):
comments = []
avatars = {user.username: user.avatar_file for user in User.query.all()}
cu = current_user.username if current_user.is_authenticated else None
user_cookies = 0
if current_user.is_authenticated:
user_cookies_record = Cookies.query.filter_by(username=current_user.username).first()
user_cookies = user_cookies_record.cookies if user_cookies_record else 0
if content_type == 'art':
content = Image.query.get_or_404(id)
comments = Comments.query.filter_by(image_id=id).order_by(Comments.comment_date.desc()).all()
if current_user.is_authenticated:
existing_view = Views.query.filter_by(image_id=id, username=current_user.username).first()
if not existing_view:
new_view = Views(image_id=id, username=current_user.username)
db.session.add(new_view)
db.session.commit()
search_query = request.args.get('search')
page = request.args.get('page', 1, type=int)
subscriptions = []
if current_user.is_authenticated:
subscriptions = [
sub.author.username
for sub in Subscription.query.filter_by(user_id=current_user.id).all()
]
query = get_content_query(Image, subscriptions, search_query)
all_images = query.all()
image_ids = [image.id for image in all_images]
current_index = image_ids.index(id)
prev_index = (current_index - 1) % len(image_ids)
next_index = (current_index + 1) % len(image_ids)
prev_content = all_images[prev_index]
next_content = all_images[next_index]
random_content = random.choice(all_images)
elif content_type == 'video':
content = Video.query.get_or_404(id)
comments = Comments.query.filter_by(video_id=id).order_by(Comments.comment_date.desc()).all()
if current_user.is_authenticated:
existing_view = Views.query.filter_by(video_id=id, username=current_user.username).first()
if not existing_view:
new_view = Views(video_id=id, username=current_user.username)
db.session.add(new_view)
db.session.commit()
all_videos = Video.query.order_by(Video.id).all()
video_ids = [video.id for video in all_videos]
current_index = video_ids.index(id)
prev_index = (current_index - 1) % len(all_videos)
next_index = (current_index + 1) % len(all_videos)
prev_content = all_videos[prev_index]
next_content = all_videos[next_index]
random_content = random.choice(all_videos)
elif content_type == 'comic':
content = Comic.query.get_or_404(id)
comments = Comments.query.filter_by(comic_id=id).order_by(Comments.comment_date.desc()).all()
if current_user.is_authenticated:
existing_view = Views.query.filter_by(image_id=id, username=current_user.username).first()
if not existing_view:
new_view = Views(image_id=id, username=current_user.username)
db.session.add(new_view)
db.session.commit()
comic_pages = ComicPage.query.filter_by(comic_id=id).order_by(ComicPage.page_number).all()
if not comic_pages:
return render_template('error.html', message="Comic pages not found")
all_comics = Comic.query.order_by(Comic.id).all()
comic_ids = [comic.id for comic in all_comics]
current_index = comic_ids.index(id)
prev_index = (current_index - 1) % len(all_comics)
next_index = (current_index + 1) % len(all_comics)
prev_content = all_comics[prev_index]
next_content = all_comics[next_index]
random_content = random.choice(all_comics)
else:
abort(404)
if request.method == 'POST' and current_user.is_authenticated:
comment_text = request.form.get('comment')
max_comment_length = 44
if comment_text and len(comment_text) > max_comment_length:
return redirect(url_for('view', content_type=content_type, id=id))
if comment_text:
new_comment = None
if content_type == 'art':
new_comment = Comments(username=cu, image_id=id, comment_text=comment_text)
elif content_type == 'video':
new_comment = Comments(username=cu, video_id=id, comment_text=comment_text)
elif content_type == 'comic':
new_comment = Comments(username=cu, comic_id=id, comment_text=comment_text)
if new_comment:
db.session.add(new_comment)
db.session.commit()
return redirect(url_for('view', content_type=content_type, id=id))
return render_template(
'view.html',
content=content,
content_type=content_type,
comments=comments,
avatars=avatars,
prev_content=prev_content,
next_content=next_content,
random_content=random_content,
user_cookies=user_cookies,
comic_pages=comic_pages if content_type == 'comic' else None
)
@app.route('/images')
def drawings():
return render_template(
'images.html'
)
@app.route('/tags_list/<page_type>')
def tags_list(page_type):
comics_tags = [comic.tags for comic in Comic.query.all() if comic.tags]
images_tags = [image.tags for image in Image.query.all() if image.tags]
videos_tags = [video.tags for video in Video.query.all() if video.tags]
if page_type == 'video':
all_tags = [tag.strip() for tags in videos_tags for tag in tags.split(',')]
elif page_type == 'comic':
all_tags = [tag.strip() for tags in comics_tags for tag in tags.split(',')]
elif page_type == 'image':
all_tags = [tag.strip() for tags in images_tags for tag in tags.split(',')]
else:
all_tags = set(tag.strip() for tags in (comics_tags + images_tags + videos_tags) for tag in tags.split(','))
sorted_tags = sorted(set(all_tags))
return render_template('tags_list.html', tags=sorted_tags, page_type=page_type)
@app.route('/subnav')
def subnav():
return render_template(
'subnav.html'
)
@app.route('/image_edit/<int:id>', methods=['GET', 'POST'])
@login_required
def image_edit(id):
image = Image.query.get_or_404(id)
if image.username != current_user.username:
return redirect(url_for('index'))
form = EditTagsForm()
if form.validate_on_submit():
image.tags = form.tags.data
db.session.commit()
return redirect(url_for('view', content_type='art', id=id))
if request.method == 'GET':
form.tags.data = image.tags
image_preview_url = url_for('static', filename=f'arts/{image.image_file}')
return render_template(
'image_edit.html',
form=form,
image=image,
image_preview_url=image_preview_url
)
@app.route('/video_edit/<int:id>', methods=['GET', 'POST'])
@login_required
async def video_edit(id):
video = Video.query.get_or_404(id)
if video.username != current_user.username:
return redirect(url_for('index'))
form = EditVideoForm()
if request.method == 'GET':
form.video_name.data = video.video_name
form.description.data = video.description
form.tags.data = video.tags
if form.validate_on_submit():
video.video_name = form.video_name.data
video.description = form.description.data
video.tags = form.tags.data
if form.video_thumbnail.data:
thumbnail_file = form.video_thumbnail.data
if allowed_file(thumbnail_file.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
thumbnail_filename = await generate_unique_filename(
app.config['UPLOAD_FOLDER']['thumbnails'], 'webp'
)
thumbnail_path = os.path.join(app.config['UPLOAD_FOLDER']['thumbnails'], thumbnail_filename)
webp_thumbnail = await convert_to_webp(thumbnail_file)
async with aiofiles.open(thumbnail_path, 'wb') as f:
await f.write(webp_thumbnail.read())
video.video_thumbnail_file = thumbnail_filename
db.session.commit()
return redirect(url_for('view', content_type='video', id=id))
video_preview_url = url_for('static', filename=f'videos/{video.video_thumbnail_file}')
return render_template(
'video_edit.html',
form=form,
video=video,
video_preview_url=video_preview_url
)
@app.route('/navbar')
def navbar():
return render_template(
'navbar.html'
)
@app.route('/card')
def card():
return render_template(
'card.html'
)
@app.route('/gifs')
def gifs():
return render_template(
'gifs.html'
)
@app.route('/autocomplete')
def autocomplete():
search_query = request.args.get('search', '', type=str)
if search_query:
suggestions = get_autocomplete_suggestions(search_query)
else:
suggestions = []
return jsonify(suggestions)
@app.route('/user_pubs/<pub_type>/<username>')
def user_pubs(pub_type, username):
p = request.args.get('page', 1, type=int)
search_query = request.args.get('search', '')
if pub_type == 'arts':
query = Image.query.filter_by(username=username)
if search_query:
query = query.filter(or_(
Image.image_file.ilike(f'%{search_query}%'),
Image.tags.ilike(f'%{search_query}%')
))
items = query.order_by(Image.publication_date.desc()).paginate(page=p, per_page=25, error_out=False)
elif pub_type == 'videos':
query = Video.query.filter_by(username=username)
if search_query:
query = query.filter(Video.video_name.ilike(f'%{search_query}%'))
items = query.order_by(Video.publication_date.desc()).paginate(page=p, per_page=25, error_out=False)
elif pub_type == 'comics':
query = Comic.query.filter_by(username=username)
if search_query:
query = query.filter(Comic.name.ilike(f'%{search_query}%'))
items = query.order_by(Comic.publication_date.desc()).paginate(page=p, per_page=25, error_out=False)
else:
abort(404)
user_cookies = Cookies.query.filter_by(username=username).first()
cookies_count = user_cookies.cookies if user_cookies else 0
return render_template(
'user_pubs.html',
items=items.items,
pagination=items,
pub_type=pub_type,
username=username,
cookies_count=cookies_count,
search_query=search_query
)
@app.route('/delete/<content_type>/<int:content_id>', methods=['POST'])
@login_required
def delete(content_type, content_id):
if content_type == 'art':
content = Image.query.get_or_404(content_id)
file_path = os.path.join(app.config['UPLOAD_FOLDER']['arts'], content.image_file)
elif content_type == 'video':
content = Video.query.get_or_404(content_id)
file_path = os.path.join(app.config['UPLOAD_FOLDER']['videos'], content.video_file)
elif content_type == 'comic':
content = Comic.query.get_or_404(content_id)
file_path = os.path.join(app.config['UPLOAD_FOLDER']['comics'], content.comic_folder)
else:
abort(404, "Invalid content type")
if content.username != current_user.username:
abort(403)
if os.path.exists(file_path):
if os.path.isdir(file_path):
shutil.rmtree(file_path)
else:
os.remove(file_path)
db.session.delete(content)
db.session.commit()
return redirect(url_for('profile', username=current_user.username))
@app.route('/delete_comment/<int:comment_id>', methods=['POST'])
@login_required
def delete_comment(comment_id):
comment = db.session.get(Comments, comment_id) or abort(404)
if comment.image_id:
content_type = 'art'
content_id = comment.image_id
elif comment.video_id:
content_type = 'video'
content_id = comment.video_id
else:
content_type = 'comic'
content_id = comment.comic_id
if comment.username == current_user.username:
try:
if hasattr(comment, 'post_id') and comment.post_id:
post_id = comment.post_id
db.session.delete(comment)
db.session.commit()
return redirect(url_for('user_posts', username=current_user.username))
db.session.delete(comment)
db.session.commit()
return redirect(url_for('view', content_type=content_type, id=content_id))
except IntegrityError:
db.session.rollback()
return redirect(url_for('view', content_type=content_type, id=content_id))
return redirect(request.referrer or url_for('index'))
@app.route('/videos')
def videos():
page = request.args.get('page', 1, type=int)
search_query = request.args.get('search')
subscriptions = []
if current_user.is_authenticated:
subscriptions = [sub.author_id for sub in Subscription.query.filter_by(user_id=current_user.id).all()]
query = get_content_query(Video, subscriptions, search_query)
pagination = query.paginate(page=page, per_page=10, error_out=False)
videos_with_views = []
for video in pagination.items:
views_count = db.session.query(func.count(Views.id)).filter(Views.video_id == video.id).scalar()
videos_with_views.append({
'video': video,
'views_count': views_count
})
popular_videos = [
{
'video': video[0],
'views_count': video[1]
}
for video in db.session.query(Video, func.count(Views.id).label('views_count'))
.outerjoin(Views, Views.video_id == Video.id)
.group_by(Video.id)
.order_by(func.count(Views.id).desc(), Video.cookie_votes.desc())
.limit(8)
.all()
]
most_viewed_videos = [
{
'video': video[0],
'views_count': video[1]
}
for video in db.session.query(Video, func.count(Views.id).label('views_count'))
.outerjoin(Views, Views.video_id == Video.id)
.group_by(Video.id)
.order_by(func.count(Views.id).desc())
.limit(8)
.all()
]
videos_tags = [video.tags for video in Video.query.all() if video.tags]
all_tags = [tag.strip() for tags in videos_tags for tag in tags.split(',')]
sorted_tags = sorted(set(all_tags))
user_cookies = 0
if current_user.is_authenticated:
user_cookies_record = Cookies.query.filter_by(username=current_user.username).first()
user_cookies = user_cookies_record.cookies if user_cookies_record else 0
return render_template(
'videos.html',
videos=videos_with_views,
pagination=pagination,
user_cookies=user_cookies,
search_query=search_query,
content_type='video',
tags=sorted_tags,
popular_videos=popular_videos,
most_viewed_videos=most_viewed_videos
)
@app.route('/vote_video/<int:video_id>', methods=['POST'])
@login_required
def vote_video(video_id):
video = Video.query.get_or_404(video_id)
user_cookies = Cookies.query.filter_by(username=current_user.username).first()
if video.username == current_user.username:
return redirect(url_for('view', content_type='video', id=video_id))
if user_cookies and user_cookies.cookies > 0:
existing_vote = VideoVotes.query.filter_by(username=current_user.username, video_id=video_id).first()
if not existing_vote:
user_cookies.cookies -= 1
video.cookie_votes += 1
new_vote = VideoVotes(username=current_user.username, video_id=video.id)
db.session.add(new_vote)
db.session.commit()
return redirect(url_for('view', content_type='video', id=video_id))
@app.route('/comics')
def comics():
page = request.args.get('page', 1, type=int)
search_query = request.args.get('search')
subscriptions = []
if current_user.is_authenticated:
subscriptions = [sub.author_id for sub in Subscription.query.filter_by(user_id=current_user.id).all()]
query = get_content_query(Comic, subscriptions, search_query)
pagination = query.paginate(page=page, per_page=10, error_out=False)
user_cookies = 0
if current_user.is_authenticated:
user_cookies_record = Cookies.query.filter_by(username=current_user.username).first()
user_cookies = user_cookies_record.cookies if user_cookies_record else 0
return render_template(
'comics.html',
comics=pagination.items,
pagination=pagination,
user_cookies=user_cookies,
search_query=search_query,
content_type='comic'
)
@app.route('/vote_comic/<int:comic_id>', methods=['POST'])
@login_required
def vote_comic(comic_id):
comic = Comic.query.get_or_404(comic_id)
user_cookies = Cookies.query.filter_by(username=current_user.username).first()
if comic.username == current_user.username:
return redirect(url_for('view', content_type='comic', id=comic_id))
if user_cookies and user_cookies.cookies > 0:
existing_vote = ComicVotes.query.filter_by(username=current_user.username, comic_id=comic_id).first()
if not existing_vote:
user_cookies.cookies -= 1
comic.cookie_votes += 1
new_vote = ComicVotes(username=current_user.username, comic_id=comic.id)
db.session.add(new_vote)
db.session.commit()
return redirect(url_for('view', content_type='comic', id=comic_id))
@app.route('/comic_edit/<int:comic_id>', methods=['GET', 'POST'])
@login_required
async def comic_edit(comic_id):
comic = Comic.query.get_or_404(comic_id)
if comic.username != current_user.username:
return redirect(url_for('index'))
cfp = os.path.join(app.config['UPLOAD_FOLDER']['comics'], comic.name)
if not os.path.exists(cfp):
os.makedirs(cfp)
form = EmptyForm()
if request.method == 'POST' and form.validate_on_submit():
action = request.form.get('action')
if action == 'delete' and (page_id := request.form.get('page')):
page = ComicPage.query.get(page_id)
if page:
os.remove(page.file_path.replace('\\', '/'))
db.session.delete(page)
db.session.commit()
pages = ComicPage.query.filter_by(comic_id=comic.id).order_by(ComicPage.page_number).all()
for i, page in enumerate(pages, start=1):
page.page_number = i
db.session.commit()
elif action == 'update' and (page_id := request.form.get('page')) and 'new_page' in request.files:
new_page = request.files['new_page']
filename = f"{uuid.uuid4().hex}.webp"
file_path = os.path.join(cfp, filename).replace('\\', '/')
webp_image = await convert_to_webp(new_page)
async with aiofiles.open(file_path, 'wb') as f:
await f.write(webp_image.read())
page = ComicPage.query.get(page_id)
if page:
os.remove(page.file_path.replace('\\', '/'))
page.file_path = file_path
db.session.commit()
elif action == 'add' and 'new_page' in request.files:
new_page = request.files['new_page']
filename = f"{uuid.uuid4().hex}.webp"
file_path = os.path.join(cfp, filename).replace('\\', '/')
webp_image = await convert_to_webp(new_page)
async with aiofiles.open(file_path, 'wb') as f:
await f.write(webp_image.read())
page_number = (db.session.query(db.func.max(ComicPage.page_number)).filter_by(comic_id=comic.id).scalar() or 0) + 1
db.session.add(ComicPage(comic_id=comic.id, page_number=page_number, file_path=file_path))
db.session.commit()
return redirect(url_for('comic_edit', comic_id=comic.id))
comic_pages = ComicPage.query.filter_by(comic_id=comic.id).order_by(ComicPage.page_number).all()
return render_template('comic_edit.html', comic=comic, comic_pages=comic_pages, form=form)
def update_related_tables(old_username, new_username):
Comments.query.filter_by(username=old_username).update({"username": new_username})
Image.query.filter_by(username=old_username).update({"username": new_username})
Video.query.filter_by(username=old_username).update({"username": new_username})
Comic.query.filter_by(username=old_username).update({"username": new_username})
Cookies.query.filter_by(username=old_username).update({"username": new_username})
Post.query.filter_by(username=old_username).update({"username": new_username})
Subscription.query.filter_by(user_id=old_username).update({"user_id": new_username})
Subscription.query.filter_by(author_id=old_username).update({"author_id": new_username})
UserItem.query.filter_by(username=old_username).update({"username": new_username})
db.session.commit()
@app.route('/profile_edit', methods=['GET', 'POST'])
@login_required
def profile_edit():
if request.method == 'POST':
section = request.form.get('section')
if section == 'avatar_banner':
avatar = request.files.get('avatar')
banner = request.files.get('banner')
if avatar and allowed_file(avatar.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
if check_file_size(avatar, app.config['MAX_IMAGE_SIZE']):
avatar_filename = secure_filename(avatar.filename)
avatar_path = os.path.join(app.config['UPLOAD_FOLDER']['avatars'], avatar_filename)
avatar.save(avatar_path)
current_user.avatar_file = avatar_filename
else:
return redirect(url_for('profile_edit'))
if banner and allowed_file(banner.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
if check_file_size(banner, app.config['MAX_IMAGE_SIZE']):
banner_filename = secure_filename(banner.filename)
banner_path = os.path.join(app.config['UPLOAD_FOLDER']['banners'], banner_filename)
banner.save(banner_path)
current_user.banner_file = banner_filename
else:
return redirect(url_for('profile_edit'))
db.session.commit()
return redirect(url_for('profile', username=current_user.username))
elif section == 'username':
new_username = request.form.get('new_username')
if new_username and new_username != current_user.username:
if len(new_username) < 3 or len(new_username) > 20:
pass
elif User.query.filter_by(username=new_username).first():
pass
else:
old_username = current_user.username
current_user.username = new_username
update_related_tables(old_username, new_username)
return redirect(url_for('profile', username=new_username))
elif section == 'bio':
bio = request.form.get('bio')
current_user.bio = bio
db.session.commit()
elif section == 'password':
current_password = request.form.get('current_password')
new_password = request.form.get('new_password')
confirm_password = request.form.get('confirm_new_password')
if not current_user.check_password(current_password):
pass
elif new_password != confirm_password:
pass
elif len(new_password) < 6:
pass
else:
current_user.encrypted_password = bcrypt.generate_password_hash(new_password).decode('utf-8')
db.session.commit()
return redirect(url_for('profile_edit'))
elif section == 'create_post':
post_text = request.form.get('post_text')
post_media = request.files.get('post_media')
if post_text:
new_post = Post(
username=current_user.username,
text=post_text
)
db.session.add(new_post)
if post_media and allowed_file(post_media.filename, app.config['ALLOWED_IMAGE_EXTENSIONS']):
if check_file_size(post_media, app.config['MAX_IMAGE_SIZE']):
media_filename = secure_filename(post_media.filename)
media_path = os.path.join(app.config['UPLOAD_FOLDER']['posts'], media_filename)
post_media.save(media_path)
new_post.media_file = media_filename
db.session.commit()
pass
else:
return redirect(url_for('profile_edit'))
db.session.commit()
return redirect(url_for('user_posts', username=current_user.username))
elif section == 'decoration':
selected_item_id = request.form.get('selected_item')
if selected_item_id:
selected_item = UserItem.query.filter_by(username=current_user.username, item_id=selected_item_id).first()
if selected_item:
current_user.current_item = selected_item.item.id
db.session.commit()
pass
else:
pass
return redirect(url_for('profile', username=current_user.username))
db.session.commit()
return redirect(url_for('profile_edit'))
return render_template(
'profile_edit.html',
user=current_user,
user_items=UserItem.query.filter_by(username=current_user.username).all()
)
@app.route('/profile/<username>')
def profile(username):
user = User.query.filter_by(username=username).first_or_404()
if not user.avatar_file:
user.avatar_file = 'default-avatar.png'
if not user.banner_file:
user.banner_file = 'default-banner.png'
total_arts = Image.query.filter_by(username=username).count()
total_videos = Video.query.filter_by(username=username).count()
total_comics = Comic.query.filter_by(username=username).count()
arts = Image.query.filter_by(username=username).order_by(Image.cookie_votes.desc(), Image.publication_date.desc()).limit(3).all()
videos = Video.query.filter_by(username=username).order_by(Video.cookie_votes.desc(), Video.publication_date.desc()).limit(3).all()
comics = Comic.query.filter_by(username=username).order_by(Comic.cookie_votes.desc(), Comic.publication_date.desc()).limit(3).all()
subscribed = (
current_user.is_authenticated and
Subscription.query.filter_by(user_id=current_user.id, author_id=user.id).first() is not None
)
current_item = Item.query.get(user.current_item) if user.current_item else None
is_current_user = current_user.is_authenticated and current_user.username == user.username
subscriptions_count = Subscription.query.filter_by(author_id=user.id).count()
return render_template(
'profile.html',
user=user,
arts=arts,
videos=videos,
comics=comics,
total_arts=total_arts,
total_videos=total_videos,
total_comics=total_comics,
current_item=current_item,
is_current_user=is_current_user,
subscribed=subscribed,
subscriptions_count=subscriptions_count
)
@app.route('/posts/<username>')
def user_posts(username):
user = User.query.filter_by(username=username).first_or_404()
posts = Post.query.filter_by(username=username).order_by(Post.post_date.desc()).all()
avatars = {user.username: user.avatar_file for user in User.query.all()}
return render_template('post.html', username=username, posts=posts, avatars=avatars)
@app.route('/posts/<username>/add_comment/<int:post_id>', methods=['POST'])
@login_required
def add_comment(username, post_id):
comment_text = request.form.get('comment_text')
if not comment_text:
return redirect(url_for('user_posts', username=username))
comment = Comments(
username=current_user.username,
post_id=post_id,
comment_text=comment_text,
comment_date=datetime.utcnow()
)
db.session.add(comment)
db.session.commit()
return redirect(url_for('user_posts', username=username))
@app.route('/subscribe/<int:author_id>', methods=['POST'])
@login_required
def subscribe(author_id):
if author_id == current_user.id:
return redirect(url_for('profile', username=current_user.username))
existing_subscription = Subscription.query.filter_by(user_id=current_user.id, author_id=author_id).first()
if existing_subscription:
return redirect(url_for('profile', username=current_user.username))
new_subscription = Subscription(user_id=current_user.id, author_id=author_id)
db.session.add(new_subscription)
db.session.commit()
return redirect(url_for('profile', username=current_user.username))
@app.route('/unsubscribe/<int:author_id>', methods=['POST'])
@login_required
def unsubscribe(author_id):
subscription = Subscription.query.filter_by(
user_id=current_user.id, author_id=author_id).first()
if subscription:
db.session.delete(subscription)
db.session.commit()
return redirect(url_for('profile', username=User.query.get(author_id).username))
@app.route('/delete_post/<int:post_id>', methods=['POST'])
@login_required
def delete_post(post_id):
try:
validate_csrf(request.form.get('csrf_token'))
except BadRequest:
return redirect(url_for('user_posts', username=current_user.username))
post = Post.query.get_or_404(post_id)
if post.username != current_user.username:
abort(403)
if post.media_file:
media_path = os.path.join(app.config['UPLOAD_FOLDER']['posts'], post.media_file)
if os.path.exists(media_path):
os.remove(media_path)
db.session.delete(post)
db.session.commit()
return redirect(url_for('user_posts', username=current_user.username))
@app.route('/privacy_policy')
def privacy_policy():
return render_template('privacy_policy.html')
@app.route('/terms_of_use')
def terms_of_use():
return render_template('terms_of_use.html')
@app.route('/publication_rules')
def publication_rules():
return render_template('publication_rules.html')
@app.context_processor
def inject_forms():
return dict(form=RegistrationForm())
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)