mgt c8 checkpoint at tests
This commit is contained in:
parent
eb0f19b109
commit
469785ee33
@ -1,3 +1,4 @@
|
|||||||
venv
|
venv
|
||||||
migrations
|
migrations
|
||||||
|
zapp.db
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
# syntax=docker/dockerfile:1.4
|
# syntax=docker/dockerfile:1.4
|
||||||
FROM python:3-slim-bookworm AS builder
|
FROM python:3-slim-bookworm AS builder
|
||||||
|
|
||||||
RUN apt update && apt install -y libmariadb-dev gcc
|
# Second line optional/debug/qol
|
||||||
|
RUN apt update && apt install -y \
|
||||||
|
libmariadb-dev gcc \
|
||||||
|
mariadb-client
|
||||||
|
|
||||||
|
|
||||||
WORKDIR /code
|
WORKDIR /code
|
||||||
COPY requirements.txt /code
|
COPY requirements.txt /code
|
||||||
|
@ -22,6 +22,10 @@ Prod only, require sys packages:
|
|||||||
pip install mariadb
|
pip install mariadb
|
||||||
pip install uwsgi
|
pip install uwsgi
|
||||||
...
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Freeze/requirements.txt. Better to audit this inside python:3-bookworm-slim container.
|
||||||
|
```
|
||||||
pip freeze > requirements.txt
|
pip freeze > requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -9,6 +9,13 @@ import pydenticon, hashlib, base64
|
|||||||
from app import db, login
|
from app import db, login
|
||||||
from flask_login import UserMixin
|
from flask_login import UserMixin
|
||||||
|
|
||||||
|
followers = sa.Table(
|
||||||
|
'followers',
|
||||||
|
db.metadata,
|
||||||
|
sa.Column('follower_id', sa.Integer, sa.ForeignKey('user.id'), primary_key=True),
|
||||||
|
sa.Column('followed_id', sa.Integer, sa.ForeignKey('user.id'), primary_key=True)
|
||||||
|
)
|
||||||
|
|
||||||
class User(UserMixin, db.Model):
|
class User(UserMixin, db.Model):
|
||||||
id: so.Mapped[int] = so.mapped_column(primary_key=True)
|
id: so.Mapped[int] = so.mapped_column(primary_key=True)
|
||||||
username: so.Mapped[str] = so.mapped_column(sa.String(64), index=True, unique=True)
|
username: so.Mapped[str] = so.mapped_column(sa.String(64), index=True, unique=True)
|
||||||
@ -17,6 +24,16 @@ class User(UserMixin, db.Model):
|
|||||||
posts: so.WriteOnlyMapped['Post'] = so.relationship(back_populates='author')
|
posts: so.WriteOnlyMapped['Post'] = so.relationship(back_populates='author')
|
||||||
about_me: so.Mapped[Optional[str]] = so.mapped_column(sa.String(140))
|
about_me: so.Mapped[Optional[str]] = so.mapped_column(sa.String(140))
|
||||||
last_seen: so.Mapped[Optional[datetime]] = so.mapped_column(default=lambda: datetime.now(timezone.utc))
|
last_seen: so.Mapped[Optional[datetime]] = so.mapped_column(default=lambda: datetime.now(timezone.utc))
|
||||||
|
following: so.WriteOnlyMapped['User'] = so.relationship(
|
||||||
|
secondary=followers,
|
||||||
|
primaryjoin=(followers.c.follower_id == id),
|
||||||
|
secondaryjoin=(followers.c.followed_id == id),
|
||||||
|
back_populates='followers')
|
||||||
|
followers: so.WriteOnlyMapped['User'] = so.relationship(
|
||||||
|
secondary=followers,
|
||||||
|
primaryjoin=(followers.c.followed_id == id),
|
||||||
|
secondaryjoin=(followers.c.follower_id == id),
|
||||||
|
back_populates='following')
|
||||||
|
|
||||||
def set_password(self, password):
|
def set_password(self, password):
|
||||||
self.password_hash = generate_password_hash(password)
|
self.password_hash = generate_password_hash(password)
|
||||||
@ -49,6 +66,36 @@ class User(UserMixin, db.Model):
|
|||||||
pngloc = os.path.join(basedir, 'usercontent', 'identicon', digest + '.png')
|
pngloc = os.path.join(basedir, 'usercontent', 'identicon', digest + '.png')
|
||||||
return pngloc
|
return pngloc
|
||||||
|
|
||||||
|
def follow(self, user):
|
||||||
|
if not self.is_following(user):
|
||||||
|
self.following.add(user)
|
||||||
|
def unfollow(self, user):
|
||||||
|
if self.is_following(user):
|
||||||
|
self.following.remove(user)
|
||||||
|
def is_following(self, user):
|
||||||
|
query = self.following.select().where(User.id == user.id)
|
||||||
|
return db.session.scalar(query) is not None
|
||||||
|
def followers_count(self):
|
||||||
|
query = sa.select(sa.func.count()).select_from(self.followers.select().subquery())
|
||||||
|
return db.session.scalar(query)
|
||||||
|
def following_count(self):
|
||||||
|
query = sa.select(sa.func.count()).select_from(self.following.select().subquery())
|
||||||
|
return db.session.scalar(query)
|
||||||
|
def following_posts(self):
|
||||||
|
Author = so.aliased(User)
|
||||||
|
Follower = so.aliased(User)
|
||||||
|
return (
|
||||||
|
sa.select(Post)
|
||||||
|
.join(Post.author.of_type(Author))
|
||||||
|
.join(Author.followers.of_type(Follower), isouter=True)
|
||||||
|
.where(sa.or_(
|
||||||
|
Follower.id == self.id
|
||||||
|
Author.id == self.id
|
||||||
|
))
|
||||||
|
.group_by(Post)
|
||||||
|
.order_by(Post.timestamp.desc())
|
||||||
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<User {}>'.format(self.username)
|
return '<User {}>'.format(self.username)
|
||||||
|
|
||||||
|
4
backend/dbdb.sh
Normal file
4
backend/dbdb.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Okay to publish -- creds are local dev only
|
||||||
|
|
||||||
|
mariadb -hdb -uflasku -pflaskp flask
|
@ -21,5 +21,9 @@ SQLAlchemy==2.0.31
|
|||||||
typing_extensions==4.12.2
|
typing_extensions==4.12.2
|
||||||
Werkzeug==3.0.3
|
Werkzeug==3.0.3
|
||||||
WTForms==3.1.2
|
WTForms==3.1.2
|
||||||
uwsgi
|
mariadb==1.1.10
|
||||||
mariadb
|
packaging==24.1
|
||||||
|
setuptools==72.1.0
|
||||||
|
uWSGI==2.0.26
|
||||||
|
wheel==0.43.0
|
||||||
|
|
||||||
|
5
backend/tests.py
Normal file
5
backend/tests.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import os
|
||||||
|
os.environ['DATABASE_URL'] = 'sqlite://'
|
||||||
|
|
||||||
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
@ -28,7 +28,10 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: backend
|
context: backend
|
||||||
target: builder
|
target: builder
|
||||||
restart: always
|
# Next two are only debug, used without restart
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
#restart: always
|
||||||
# Comment following line to use flask (1worker, dev), uncomment to use uwsgi (wsgi)
|
# Comment following line to use flask (1worker, dev), uncomment to use uwsgi (wsgi)
|
||||||
#command: ["uwsgi", "--http", "0.0.0.0:8000", "--master", "-p", "4", "-w", "microblog:app"]
|
#command: ["uwsgi", "--http", "0.0.0.0:8000", "--master", "-p", "4", "-w", "microblog:app"]
|
||||||
environment:
|
environment:
|
||||||
|
Loading…
Reference in New Issue
Block a user