Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement JSON Import Feature, Enhance Database Transactions, and Dockerize the Application #19

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM python:3.9-slim

WORKDIR /app
COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8080

CMD ["sh", "-c", "python3 updater.py & python3 app.py"]
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,15 @@ You'll need the followings:
```bash
git clone [email protected]:wow0000/friends42.git && cd friends42
pip install -r requirements.txt
cp config.sample.py config.py
vim config.py
python3 app.py
python3 updater.py
```
OR
with Docker
```bash
docker compose up --build -d
```

Then head to http://localhost:8080/
Expand Down
9 changes: 6 additions & 3 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import routes.finder
import importlib
import routes.helpers
import routes.tasks
from globals import *

if config.sentry and config.sentry != '':
sentry_sdk.init(
Expand All @@ -14,13 +16,14 @@
profiles_sample_rate=config.sentry_profiles_sample_rate
)

db = Db("database.db")
db.initialize()
with Db("database.db") as db:
db.initialize()

app = Flask(__name__)

for route in routes.finder.get_all_routes():
app.register_blueprint(importlib.import_module('routes.' + route, package=None).app)
blueprint = importlib.import_module('routes.' + route, package=None).app
app.register_blueprint(blueprint)

app.jinja_env.globals.update(len=len)
app.jinja_env.globals.update(enumerate=enumerate)
Expand Down
72 changes: 44 additions & 28 deletions db.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,63 @@
# db.py
import sqlite3
import secrets
import threading
import base64
import json
from contextlib import contextmanager
from routes.api_helpers import *


def read_file(filename: str):
with open(filename, 'r') as f:
return f.read()


def dict_factory(cursor, row) -> dict:
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d


class Db:
_lock = threading.Lock()
cur: sqlite3.Cursor = None
con: sqlite3.Connection = None
is_closed = False

def __init__(self, filename="database.db"):
self.con = sqlite3.connect(filename)
self.con.row_factory = dict_factory
self.cur = self.con.cursor()
self.conn = sqlite3.connect(
filename,
check_same_thread=False,
isolation_level=None
)
self.conn.execute('PRAGMA foreign_keys = ON')
self.conn.execute('PRAGMA journal_mode = WAL')
self.conn.execute('PRAGMA synchronous = NORMAL')
self.conn.row_factory = dict_factory
self.cur = self.conn.cursor()

# Management
def initialize(self):
self.create_table('scheme.sql')
self.close()

def commit(self):
self.con.commit()
if self.conn:
self.conn.commit()

def close(self):
self.commit()
self.con.close()
self.is_closed = True
if not self.is_closed and self.conn:
self.commit()
self.conn.close()
self.is_closed = True

@contextmanager
def transaction(self):
try:
self.cur.execute('BEGIN')
yield
self.commit()
except Exception:
self.conn.rollback()
raise

def __enter__(self):
return self
Expand Down Expand Up @@ -66,9 +85,9 @@ def god(db, field, userid: int):
campus = 1
self.cur.execute(
'INSERT OR REPLACE INTO USERS(id, name, image, image_medium, pool, active, campus) '
f"VALUES(?, ?, ?, ?, ?, {active}, {campus})",
f"VALUES(?, ?, ?, ?, ?, {active}, ?)",
[uid, user_data["login"], user_data["image"]["link"], user_data["image"]["versions"]["medium"],
f"{user_data['pool_month']} {user_data['pool_year']}"])
f"{user_data['pool_month']} {user_data['pool_year']}", campus])

def get_user(self, user_id):
query = self.cur.execute("SELECT id FROM USERS WHERE name = ?", [user_id])
Expand Down Expand Up @@ -156,7 +175,7 @@ def add_friend(self, who: int, add_id: int):
if who is None or add_id is None or add_id <= 0:
return False
self.cur.execute("INSERT OR REPLACE INTO FRIENDS(who, has) VALUES (?, ?)",
[who, add_id])
[who, add_id])
self.commit()
return True

Expand Down Expand Up @@ -186,7 +205,7 @@ def remove_friend(self, who: int, remove: int):
if who is None or remove is None or remove <= 0:
return False
self.cur.execute("DELETE FROM FRIENDS WHERE who = ? AND has = ?", [who, remove])
self.con.commit()
self.commit()
return True

def set_relation(self, who: int, has: int, relation: int):
Expand Down Expand Up @@ -226,7 +245,7 @@ def reset_user_cookies(self, who: int):
if who is None:
return False
self.cur.execute('DELETE FROM COOKIES WHERE userid = ?', [who])
self.con.commit()
self.commit()
return True

def create_cookie(self, who: int, user_agent) -> str:
Expand Down Expand Up @@ -267,7 +286,7 @@ def create_issue(self, who: int, station: str, issue: int) -> bool:
if self.already_created(who, station):
return False
self.cur.execute('INSERT INTO DEAD_PC(issuer, station, issue) VALUES(?, ?, ?)',
[who, station, issue])
[who, station, issue])
self.commit()
return True

Expand Down Expand Up @@ -302,7 +321,7 @@ def set_profile(self, who: int, info: dict) -> bool:

def get_user_profile(self, login, api=None):
query = self.cur.execute("SELECT * FROM USERS LEFT JOIN PROFILES ON PROFILES.userid = USERS.id WHERE name = ?",
[str(login)])
[str(login)])
ret = query.fetchone()
if api and ret is None:
ret_status, ret_data = api.get_unknown_user(login)
Expand All @@ -327,7 +346,6 @@ def is_banned(self, user_id: int) -> bool:
return query.fetchone() is not None

# Mates

def get_mate_by_id(self, mate_id):
req = self.cur.execute("SELECT * FROM MATES WHERE id = ?", [mate_id])
return req.fetchone()
Expand All @@ -338,20 +356,20 @@ def get_mates_by_user(self, who_id):

def get_mates(self, project: str, campus: int):
req = self.cur.execute("SELECT * FROM MATES WHERE project = ? AND campus = ? ORDER BY created DESC",
[project, campus])
[project, campus])
return req.fetchall()

def get_latest_mates(self, campus: int):
req = self.cur.execute("SELECT * FROM MATES WHERE campus = ? ORDER BY created DESC LIMIT 15",
[campus])
[campus])
return req.fetchall()

def delete_mate(self, project_id):
self.cur.execute("DELETE FROM MATES WHERE id = ?", [project_id])
self.commit()

def new_mate(self, creator: int, project: str, deadline: str, progress: int, quick_contacts: str, mates: str,
description: str, contact: str, people: int) -> int:
description: str, contact: str, people: int) -> int:
if len(quick_contacts) > 35 or len(mates) > 60 or len(description) > 1000 or len(contact) > 500 or len(
deadline) > 10:
return 1
Expand All @@ -372,7 +390,6 @@ def new_mate(self, creator: int, project: str, deadline: str, progress: int, qui
return 0

# Projects

def get_project_list(self, redis):
rds_ret = redis.get('db_project_list')
if rds_ret:
Expand Down Expand Up @@ -416,13 +433,13 @@ def is_project_a_thing(self, project_slug) -> bool:
def search_project_solo(self, keyword: str, solo: False) -> list:
keyword = f"%{keyword}%"
req = self.cur.execute("SELECT * FROM PROJECTS WHERE (name LIKE ? OR slug LIKE ?) AND solo = ?",
[keyword, keyword, solo])
[keyword, keyword, solo])
return req.fetchall()

def search_project(self, keyword: str) -> list:
keyword = f"%{keyword}%"
req = self.cur.execute("SELECT * FROM PROJECTS WHERE name LIKE ? OR slug LIKE ?",
[keyword, keyword])
[keyword, keyword])
return req.fetchall()

# Update process
Expand Down Expand Up @@ -509,11 +526,10 @@ def admin_change_tag(self, user_id: int, tag: str):
self.commit()

# Messages

def insert_message(self, author, dest, content, anon=False):
anon = 1 if anon else 0
self.cur.execute("INSERT INTO MESSAGES(author, dest, content, anonymous) VALUES(?, ?, ?, ?)",
[author, dest, content, anon])
[author, dest, content, anon])
self.commit()

def get_messages(self, dest):
Expand Down Expand Up @@ -550,5 +566,5 @@ def get_special_user_by_id(self, sp_id: int):

def update_special_user(self, key: str, sp_tag: str, sp_tag_style: str, sp_author: str):
self.cur.execute("UPDATE SPECIAL_USERS SET sp_tag = ?, sp_tag_style = ?, sp_author = ? WHERE sp_send_key = ?",
[sp_tag, sp_tag_style, sp_author, key])
[sp_tag, sp_tag_style, sp_author, key])
self.commit()
22 changes: 22 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
services:
web:
image: web:friends42
build:
context: .
ports:
- "8080:8080"
depends_on:
- redis
environment:
REDIS_HOST: redis
REDIS_PORT: 6379

redis:
image: redis:latest
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
1 change: 0 additions & 1 deletion routes/f_friends.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from flask import Blueprint, render_template
from globals import *
from routes.helpers import *
import arrow

app = Blueprint('friends', __name__, template_folder='templates')

Expand Down
Loading