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 import RecaptchaField 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'' 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'' 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'' 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'' 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'' 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 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(min=3, max=20), Regexp(r'^[a-zA-Z0-9_]+$', message="Username can contain only letters, numbers, and underscores.") ] ) 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('Применить')