|
|
@ -70,21 +70,27 @@ class TimestampMixin(object):
|
|
|
|
def natural_updated(self):
|
|
|
|
def natural_updated(self):
|
|
|
|
return humanize.naturaltime(datetime.now().astimezone(self.updated.tzinfo) - self.updated)
|
|
|
|
return humanize.naturaltime(datetime.now().astimezone(self.updated.tzinfo) - self.updated)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
user_tags_blacklist = db.Table('user_tags_blacklist', db.metadata,
|
|
|
|
|
|
|
|
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
|
|
|
|
|
|
|
|
db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class User(UserMixin, TimestampMixin, db.Model):
|
|
|
|
class User(UserMixin, TimestampMixin, db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
username = db.Column(db.String(128), unique=True, nullable=False)
|
|
|
|
username = db.Column(db.String(128), unique=True, nullable=False)
|
|
|
|
email = db.Column(db.String(256), unique=True)
|
|
|
|
email = db.Column(db.String(256), unique=True)
|
|
|
|
pass_hash = db.Column(db.String(128))
|
|
|
|
pass_hash = db.Column(db.String(128))
|
|
|
|
op_level = db.Column(db.Enum(OP_LEVEL), default=OP_LEVEL.user, nullable=False)
|
|
|
|
op_level = db.Column(db.Enum(OP_LEVEL), server_default=OP_LEVEL.user.name, nullable=False)
|
|
|
|
user_status = db.Column(db.Enum(USER_STATUS), default=USER_STATUS.active, nullable=False)
|
|
|
|
user_status = db.Column(db.Enum(USER_STATUS), server_default=USER_STATUS.active.name, nullable=False)
|
|
|
|
last_login = db.Column(UtcDateTime)
|
|
|
|
last_login = db.Column(UtcDateTime)
|
|
|
|
|
|
|
|
|
|
|
|
ban_status = None
|
|
|
|
ban_until = db.Column(UtcDateTime)
|
|
|
|
ban_until = None
|
|
|
|
ban_reason = db.Column(db.String(512))
|
|
|
|
ban_reason = None
|
|
|
|
|
|
|
|
|
|
|
|
biography = db.Column(db.String(512))
|
|
|
|
|
|
|
|
|
|
|
|
#authored_posts = db.relationship('Post', back_populates='author')
|
|
|
|
rating = db.Column(db.Enum(RATING), server_default=RATING.safe.name, nullable=False)
|
|
|
|
#approved_posts = db.relationship('Post', back_populates='approver')
|
|
|
|
tag_blacklist = db.relationship('Tag', secondary=user_tags_blacklist, backref=db.backref('user_blacklisted'))
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
def __repr__(self):
|
|
|
|
return '<User {}>'.format(self.username)
|
|
|
|
return '<User {}>'.format(self.username)
|
|
|
@ -93,8 +99,10 @@ class User(UserMixin, TimestampMixin, db.Model):
|
|
|
|
self.pass_hash = generate_password_hash(password, salt_length=16)
|
|
|
|
self.pass_hash = generate_password_hash(password, salt_length=16)
|
|
|
|
|
|
|
|
|
|
|
|
def check_password(self, password):
|
|
|
|
def check_password(self, password):
|
|
|
|
|
|
|
|
# if self.pass_hash is None:
|
|
|
|
|
|
|
|
# return True
|
|
|
|
if self.pass_hash is None:
|
|
|
|
if self.pass_hash is None:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
return check_password_hash(self.pass_hash, password)
|
|
|
|
return check_password_hash(self.pass_hash, password)
|
|
|
|
|
|
|
|
|
|
|
|
def login(self, remember):
|
|
|
|
def login(self, remember):
|
|
|
@ -146,9 +154,6 @@ def admin_required(func):
|
|
|
|
# user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
|
|
|
|
# user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
|
|
|
|
# user = db.relationship('User', backref=db.backref('profile', uselist=False))
|
|
|
|
# user = db.relationship('User', backref=db.backref('profile', uselist=False))
|
|
|
|
|
|
|
|
|
|
|
|
# rating = db.Column(db.Enum(RATING), default=RATING.safe, nullable=False)
|
|
|
|
|
|
|
|
# tag_blacklist = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
post_tags = db.Table('post_tags', db.metadata,
|
|
|
|
post_tags = db.Table('post_tags', db.metadata,
|
|
|
|
db.Column('post_id', db.Integer, db.ForeignKey('post.id')),
|
|
|
|
db.Column('post_id', db.Integer, db.ForeignKey('post.id')),
|
|
|
@ -160,7 +165,7 @@ class Post(TimestampMixin, db.Model):
|
|
|
|
md5 = db.Column(db.String(32), unique=True, nullable=False)
|
|
|
|
md5 = db.Column(db.String(32), unique=True, nullable=False)
|
|
|
|
filetype = db.Column(db.Enum(FILETYPE), nullable=False)
|
|
|
|
filetype = db.Column(db.Enum(FILETYPE), nullable=False)
|
|
|
|
rating = db.Column(db.Enum(RATING), nullable=False)
|
|
|
|
rating = db.Column(db.Enum(RATING), nullable=False)
|
|
|
|
status = db.Column(db.Enum(POST_STATUS), default=POST_STATUS.pending, nullable=False)
|
|
|
|
status = db.Column(db.Enum(POST_STATUS), server_default=POST_STATUS.pending.name, nullable=False)
|
|
|
|
|
|
|
|
|
|
|
|
width = db.Column(db.Integer, default=0)
|
|
|
|
width = db.Column(db.Integer, default=0)
|
|
|
|
height = db.Column(db.Integer, default=0)
|
|
|
|
height = db.Column(db.Integer, default=0)
|
|
|
@ -189,6 +194,8 @@ class Post(TimestampMixin, db.Model):
|
|
|
|
|
|
|
|
|
|
|
|
self.origin_filename = file.filename
|
|
|
|
self.origin_filename = file.filename
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.generate_image_files(file)
|
|
|
|
|
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
def __repr__(self):
|
|
|
|
return('<Post #{} by {}, {} of {} bytes>'.format(self.id, self.author, self.filetype.name, self.filesize))
|
|
|
|
return('<Post #{} by {}, {} of {} bytes>'.format(self.id, self.author, self.filetype.name, self.filesize))
|
|
|
|
|
|
|
|
|
|
|
@ -197,7 +204,7 @@ class Post(TimestampMixin, db.Model):
|
|
|
|
return "flex: {0:.2f} 1 {0:.2f}px;".format(self.width/self.height*current_app.config.get('POST_LIST_THUMB_HEIGHT', 240))
|
|
|
|
return "flex: {0:.2f} 1 {0:.2f}px;".format(self.width/self.height*current_app.config.get('POST_LIST_THUMB_HEIGHT', 240))
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def image_url(self):
|
|
|
|
def file_uri(self):
|
|
|
|
# filename = "{}.{}".format('maybe_later_generated_cute_filename', 'jpg' if self.filetype is FILETYPE.jpeg else 'png')
|
|
|
|
# filename = "{}.{}".format('maybe_later_generated_cute_filename', 'jpg' if self.filetype is FILETYPE.jpeg else 'png')
|
|
|
|
# filename = 'maybe_later_generated_cute_filename'
|
|
|
|
# filename = 'maybe_later_generated_cute_filename'
|
|
|
|
filename = "{} - {} {}".format(current_app.config.get('INSTANCE_NAME'), self.id, " ".join(tag.content.replace(' ', '_') for tag in self.tags))
|
|
|
|
filename = "{} - {} {}".format(current_app.config.get('INSTANCE_NAME'), self.id, " ".join(tag.content.replace(' ', '_') for tag in self.tags))
|
|
|
@ -213,28 +220,39 @@ class Post(TimestampMixin, db.Model):
|
|
|
|
elif endpoint == 'thumb':
|
|
|
|
elif endpoint == 'thumb':
|
|
|
|
return url_for('main.uploaded_thumb', path="{}.{}".format(path,'jpg'))
|
|
|
|
return url_for('main.uploaded_thumb', path="{}.{}".format(path,'jpg'))
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
|
|
|
def image_path(self):
|
|
|
|
|
|
|
|
filename = "{}.{}".format(self.md5, 'jpg' if self.filetype is FILETYPE.jpeg else 'png')
|
|
|
|
|
|
|
|
return os.path.join(current_app.config.get('POST_UPLOADS'), 'img', filename)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
def generate_image_files(self, file):
|
|
|
|
def jpeg_path(self):
|
|
|
|
with open(self.image_files['image'], "wb") as f:
|
|
|
|
if self.filetype is FILETYPE.jpeg:
|
|
|
|
f.write(file.data.getbuffer())
|
|
|
|
return None
|
|
|
|
# file.seek(0)
|
|
|
|
|
|
|
|
# file.save(post.image_path)
|
|
|
|
|
|
|
|
|
|
|
|
jpeg_filename = "{}.{}".format(self.md5, 'jpg')
|
|
|
|
with Image.open(file.data) as im:
|
|
|
|
return os.path.join(current_app.config.get('POST_UPLOADS'), 'jpeg', jpeg_filename)
|
|
|
|
im = im.convert('RGB')
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
if self.image_files['jpeg'] is not None:
|
|
|
|
def sample_path(self):
|
|
|
|
im.save(self.image_files['jpeg'], 'JPEG', quality=80)
|
|
|
|
jpeg_filename = "{}.{}".format(self.md5, 'jpg')
|
|
|
|
|
|
|
|
return os.path.join(current_app.config.get('POST_UPLOADS'), 'sample', jpeg_filename)
|
|
|
|
sim = im.copy()
|
|
|
|
|
|
|
|
sim.thumbnail([800,800])
|
|
|
|
|
|
|
|
sim.save(self.image_files['sample'], 'JPEG', quality=80)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
sim = im.copy()
|
|
|
|
|
|
|
|
sim.thumbnail([512,512])
|
|
|
|
|
|
|
|
sim.save(self.image_files['thumb'], 'JPEG', quality=80)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_image_files(self):
|
|
|
|
|
|
|
|
for im in self.image_files.values():
|
|
|
|
|
|
|
|
os.remove(im)
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def thumb_path(self):
|
|
|
|
def image_files(self):
|
|
|
|
jpeg_filename = "{}.{}".format(self.md5, 'jpg')
|
|
|
|
return dict(
|
|
|
|
return os.path.join(current_app.config.get('POST_UPLOADS'), 'thumb', jpeg_filename)
|
|
|
|
image=os.path.join(current_app.config.get('POST_UPLOADS'), 'img', "{}.{}".format(self.md5, 'jpg' if self.filetype is FILETYPE.jpeg else 'png')),
|
|
|
|
|
|
|
|
jpeg=(None if self.filetype is FILETYPE.jpeg else os.path.join(current_app.config.get('POST_UPLOADS'), 'jpeg', "{}.{}".format(self.md5, 'jpg'))),
|
|
|
|
|
|
|
|
sample=os.path.join(current_app.config.get('POST_UPLOADS'), 'sample', "{}.{}".format(self.md5, 'jpg')),
|
|
|
|
|
|
|
|
thumb=os.path.join(current_app.config.get('POST_UPLOADS'), 'thumb', "{}.{}".format(self.md5, 'jpg'))
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
@cached_property
|
|
|
|
def image_resolution(self):
|
|
|
|
def image_resolution(self):
|
|
|
@ -257,7 +275,7 @@ class Post(TimestampMixin, db.Model):
|
|
|
|
class Tag(TimestampMixin, db.Model):
|
|
|
|
class Tag(TimestampMixin, db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
content = db.Column(db.String(128), unique=True, nullable=False)
|
|
|
|
content = db.Column(db.String(128), unique=True, nullable=False)
|
|
|
|
category = db.Column(db.Enum(TAG_CATEGORY), default=TAG_CATEGORY.general, nullable=False)
|
|
|
|
category = db.Column(db.Enum(TAG_CATEGORY), server_default=TAG_CATEGORY.general.name, nullable=False)
|
|
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
@property
|
|
|
|
def content_deser(self):
|
|
|
|
def content_deser(self):
|
|
|
|