264 lines
12 KiB
Python
264 lines
12 KiB
Python
import os
|
|
import io
|
|
import re
|
|
import uuid
|
|
import shutil
|
|
import random
|
|
import asyncio
|
|
from datetime import datetime
|
|
import requests
|
|
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, flash, 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 flask_wtf import FlaskForm
|
|
from wtforms import StringField, PasswordField, SubmitField, FileField, BooleanField
|
|
from wtforms.validators import DataRequired
|
|
from flask_wtf.file import FileAllowed
|
|
|
|
db = SQLAlchemy()
|
|
bcrypt = Bcrypt()
|
|
|
|
class Comments(db.Model):
|
|
__tablename__ = 'comments'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String, nullable=False)
|
|
image_id = db.Column(db.Integer, db.ForeignKey('image.id'), nullable=True)
|
|
video_id = db.Column(db.Integer, db.ForeignKey('video.id'), nullable=True)
|
|
comic_id = db.Column(db.Integer, db.ForeignKey('comics.id'), nullable=True)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
|
|
comment_text = db.Column(db.Text, nullable=False)
|
|
comment_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
image = db.relationship('Image', back_populates='comments')
|
|
video = db.relationship('Video', back_populates='comments')
|
|
comic = db.relationship('Comic', back_populates='comments', overlaps="comic_link")
|
|
post = db.relationship('Post', backref='comments')
|
|
|
|
class User(db.Model, UserMixin):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(20), unique=True, nullable=False)
|
|
encrypted_password = db.Column(db.String(60), nullable=False)
|
|
ip_address = db.Column(db.String(15), nullable=True)
|
|
avatar_file = db.Column(db.String(50), nullable=True)
|
|
banner_file = db.Column(db.String(50), nullable=True)
|
|
bio = db.Column(db.Text, nullable=True)
|
|
current_item = db.Column(db.String(30), nullable=True)
|
|
|
|
def __repr__(self):
|
|
return f'<User {self.username}>'
|
|
|
|
def check_password(self, password):
|
|
return bcrypt.check_password_hash(self.encrypted_password, password)
|
|
|
|
class Image(db.Model):
|
|
__tablename__ = 'image'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
image_file = db.Column(db.String(40), nullable=False)
|
|
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
|
|
publication_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
tags = db.Column(db.String(100), nullable=True)
|
|
cookie_votes = db.Column(db.Integer, default=0)
|
|
|
|
comments = db.relationship('Comments', back_populates='image', cascade='all, delete-orphan')
|
|
|
|
class Votes(db.Model):
|
|
__tablename__ = 'votes'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(100), nullable=False)
|
|
image_id = db.Column(db.Integer, db.ForeignKey('image.id'), nullable=False)
|
|
|
|
image = db.relationship('Image', backref=db.backref('votes', lazy=True))
|
|
|
|
def __repr__(self):
|
|
return f'<Vote {self.username} for image {self.image_id}>'
|
|
|
|
class VideoVotes(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(120), nullable=False)
|
|
video_id = db.Column(db.Integer, db.ForeignKey('video.id'), nullable=False)
|
|
|
|
class Video(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
video_file = db.Column(db.String(100), nullable=False)
|
|
video_name = db.Column(db.String(100), nullable=False)
|
|
video_thumbnail_file = db.Column(db.String(100), nullable=False)
|
|
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
|
|
publication_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
tags = db.Column(db.String(100), nullable=True)
|
|
description = db.Column(db.Text, nullable=True)
|
|
cookie_votes = db.Column(db.Integer, default=0)
|
|
|
|
comments = db.relationship('Comments', back_populates='video')
|
|
|
|
class Comic(db.Model):
|
|
__tablename__ = 'comics'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
comic_folder = db.Column(db.String(100), nullable=False)
|
|
comic_thumbnail_file = db.Column(db.String(100), nullable=False)
|
|
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
|
|
name = db.Column(db.String(100), nullable=False, unique=True)
|
|
publication_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
tags = db.Column(db.String(100), nullable=True)
|
|
cookie_votes = db.Column(db.Integer, default=0)
|
|
|
|
comments = db.relationship('Comments', back_populates='comic', overlaps="comic_link")
|
|
pages = db.relationship('ComicPage', back_populates='comic', cascade="all, delete-orphan")
|
|
|
|
class ComicPage(db.Model):
|
|
__tablename__ = 'comic_pages'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
comic_id = db.Column(db.Integer, db.ForeignKey('comics.id', ondelete='CASCADE'), nullable=False)
|
|
page_number = db.Column(db.Integer, nullable=False)
|
|
file_path = db.Column(db.String(200), nullable=False)
|
|
|
|
comic = db.relationship('Comic', back_populates='pages')
|
|
|
|
class ComicVotes(db.Model):
|
|
__tablename__ = 'comic_votes'
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(100), nullable=False)
|
|
comic_id = db.Column(db.Integer, db.ForeignKey('comics.id'), nullable=False)
|
|
vote = db.Column(db.Integer)
|
|
|
|
comic = db.relationship('Comic', backref='votes', lazy=True)
|
|
|
|
class Cookies(db.Model):
|
|
username = db.Column(db.String(20), primary_key=True, nullable=False)
|
|
cookies = db.Column(db.Integer, default=0)
|
|
|
|
class Views(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
|
image_id = db.Column(db.Integer, db.ForeignKey('image.id'), nullable=True)
|
|
video_id = db.Column(db.Integer, db.ForeignKey('video.id'), nullable=True)
|
|
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
|
|
view_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
__table_args__ = (
|
|
db.UniqueConstraint('image_id', 'username', name='unique_image_view'),
|
|
db.UniqueConstraint('video_id', 'username', name='unique_video_view')
|
|
)
|
|
|
|
class Item(db.Model):
|
|
__tablename__ = 'items'
|
|
|
|
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
|
item_path = db.Column(db.String, nullable=False)
|
|
price = db.Column(db.Integer, nullable=False, default=0)
|
|
visible = db.Column(db.Boolean, default=True)
|
|
|
|
def __repr__(self):
|
|
return f'<Item {self.id}: {self.item_path}, Price: {self.price}, Visible: {self.visible}>'
|
|
|
|
class UserItem(db.Model):
|
|
__tablename__ = 'user_items'
|
|
|
|
username = db.Column(db.String, db.ForeignKey('user.username'), primary_key=True)
|
|
item_id = db.Column(db.Integer, db.ForeignKey('items.id'), primary_key=True)
|
|
|
|
item = db.relationship('Item', backref=db.backref('user_items', lazy=True))
|
|
|
|
def __repr__(self):
|
|
return f'<UserItem {self.username}, Item {self.item_id}>'
|
|
|
|
class Post(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
username = db.Column(db.String(20), db.ForeignKey('user.username'), nullable=False)
|
|
post_date = db.Column(db.DateTime, default=datetime.utcnow)
|
|
text = db.Column(db.Text, nullable=False)
|
|
media_file = db.Column(db.String(100), nullable=True)
|
|
|
|
user = db.relationship('User', backref=db.backref('posts', lazy=True))
|
|
|
|
class Subscription(db.Model):
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
user = db.relationship('User', foreign_keys=[user_id], backref=db.backref('subscriptions', lazy=True))
|
|
author = db.relationship('User', foreign_keys=[author_id], backref=db.backref('followers', lazy=True))
|
|
|
|
def __repr__(self):
|
|
return f'<Subscription user_id={self.user_id} author_id={self.author_id}>'
|
|
|
|
class UploadForm(FlaskForm):
|
|
image_file = FileField('Choose File', validators=[DataRequired()])
|
|
tags = StringField('Tags (comma-separated)', validators=[DataRequired()])
|
|
recaptcha = RecaptchaField()
|
|
agree_with_rules = BooleanField('I agree with the publication rules',
|
|
validators=[DataRequired(message="You must agree with the publication rules.")])
|
|
submit = SubmitField('Upload')
|
|
|
|
class UploadVideoForm(FlaskForm):
|
|
video_file = FileField('Video File', validators=[DataRequired()])
|
|
thumbnail = FileField('Thumbnail', validators=[DataRequired(), FileAllowed(['jpg', 'png', 'jpeg'])])
|
|
name = StringField('Video Name', validators=[DataRequired()])
|
|
tags = StringField('Tags', validators=[DataRequired()])
|
|
description = StringField('Description', validators=[DataRequired()])
|
|
recaptcha = RecaptchaField()
|
|
submit = SubmitField('Upload')
|
|
agree_with_rules = BooleanField('I agree with the publication rules', validators=[DataRequired()])
|
|
|
|
class UploadComicForm(FlaskForm):
|
|
title = StringField('Comic Name', validators=[DataRequired()])
|
|
thumbnail = FileField('Thumbnail', validators=[DataRequired()])
|
|
tags = StringField('Tags (comma-separated)')
|
|
recaptcha = RecaptchaField()
|
|
agree_with_rules = BooleanField('I agree with the publication rules', validators=[DataRequired(message="You must agree with the publication rules.")])
|
|
submit = SubmitField('Upload')
|
|
|
|
class EditTagsForm(FlaskForm):
|
|
tags = StringField('Tags', validators=[DataRequired(), Length(max=100)], render_kw={"placeholder": "Enter tags"})
|
|
submit = SubmitField('Save')
|
|
|
|
class EditVideoForm(FlaskForm):
|
|
video_name = StringField('Title', validators=[DataRequired(), Length(max=100)], render_kw={"placeholder": "Enter video title"})
|
|
video_thumbnail = FileField('Thumbnail', validators=[FileAllowed(['jpg', 'jpeg', 'png', 'gif'], 'Only images!')])
|
|
description = TextAreaField('Description', validators=[DataRequired(), Length(max=500)], render_kw={"placeholder": "Enter video description"})
|
|
tags = StringField('Tags', validators=[DataRequired(), Length(max=100)], render_kw={"placeholder": "Tags"})
|
|
submit = SubmitField('Save')
|
|
|
|
class LoginForm(FlaskForm):
|
|
username = StringField('Username', validators=[DataRequired()])
|
|
password = PasswordField('Password', validators=[DataRequired()])
|
|
recaptcha = RecaptchaField()
|
|
submit = SubmitField('Login')
|
|
|
|
|
|
class RegistrationForm(FlaskForm):
|
|
username = StringField('Username',
|
|
validators=[DataRequired(), Length(3,20),
|
|
Regexp('^[a-zA-Z0-9_]+$')])
|
|
password = PasswordField('Password',
|
|
validators=[DataRequired(), Length(min=6)])
|
|
confirm_password = PasswordField('Confirm Password',
|
|
validators=[DataRequired(), EqualTo('password')])
|
|
recaptcha = RecaptchaField()
|
|
submit = SubmitField('Register')
|
|
|
|
class EmptyForm(FlaskForm):
|
|
pass
|
|
|
|
class UpdateCookiesForm(FlaskForm):
|
|
cookies = StringField('Количество печенек', validators=[DataRequired()])
|
|
submit = SubmitField('Применить') |