WIP
This commit is contained in:
parent
637b00261a
commit
3c4a25e5ad
17 changed files with 197 additions and 272 deletions
|
|
@ -1,3 +0,0 @@
|
|||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
|
@ -1,3 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import profig
|
||||
|
||||
# constants
|
||||
FLASK_APP = "flask.app"
|
||||
|
||||
DB_URL = "main.db_url"
|
||||
|
||||
HTTP_HOST = "http.host"
|
||||
HTTP_PORT = "http.port"
|
||||
|
||||
SECURITY_SALT = "security.salt"
|
||||
SECURITY_SECRET = "security.secret"
|
||||
|
||||
MAIL_POLLING = "polling.newmail"
|
||||
COMMENT_POLLING = "polling.newcomment"
|
||||
|
||||
# variable
|
||||
params = dict()
|
||||
|
||||
|
||||
def initialize(config_pathname, flask_app):
|
||||
cfg = profig.Config(config_pathname)
|
||||
cfg.sync()
|
||||
params.update(cfg)
|
||||
params.update({FLASK_APP: flask_app})
|
||||
|
||||
|
||||
def get(key):
|
||||
return params[key]
|
||||
|
||||
|
||||
def getInt(key):
|
||||
return int(params[key])
|
||||
|
||||
|
||||
def _str2bool(v):
|
||||
return v.lower() in ("yes", "true", "t", "1")
|
||||
|
||||
|
||||
def getBool(key):
|
||||
return _str2bool(params[key])
|
||||
|
||||
|
||||
def flaskapp():
|
||||
return params[FLASK_APP]
|
||||
|
|
|
|||
|
|
@ -1,115 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created with https://app.quicktype.io
|
||||
# name: stacosys
|
||||
|
||||
json_schema = """
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-06/schema#",
|
||||
"$ref": "#/definitions/Welcome",
|
||||
"definitions": {
|
||||
"Welcome": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"general": {
|
||||
"$ref": "#/definitions/General"
|
||||
},
|
||||
"http": {
|
||||
"$ref": "#/definitions/HTTP"
|
||||
},
|
||||
"security": {
|
||||
"$ref": "#/definitions/Security"
|
||||
},
|
||||
"rss": {
|
||||
"$ref": "#/definitions/RSS"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"general",
|
||||
"http",
|
||||
"rss",
|
||||
"security"
|
||||
],
|
||||
"title": "Welcome"
|
||||
},
|
||||
"General": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"debug": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"lang": {
|
||||
"type": "string"
|
||||
},
|
||||
"db_url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"db_url",
|
||||
"debug",
|
||||
"lang"
|
||||
],
|
||||
"title": "General"
|
||||
},
|
||||
"HTTP": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"root_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"host": {
|
||||
"type": "string"
|
||||
},
|
||||
"port": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"host",
|
||||
"port",
|
||||
"root_url"
|
||||
],
|
||||
"title": "HTTP"
|
||||
},
|
||||
"RSS": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"proto": {
|
||||
"type": "string"
|
||||
},
|
||||
"file": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"file",
|
||||
"proto"
|
||||
],
|
||||
"title": "RSS"
|
||||
},
|
||||
"Security": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"salt": {
|
||||
"type": "string"
|
||||
},
|
||||
"secret": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"salt",
|
||||
"secret"
|
||||
],
|
||||
"title": "Security"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from flask import Flask
|
||||
from conf import config
|
||||
from jsonschema import validate
|
||||
from flask_apscheduler import APScheduler
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
# add current path and parent path to syspath
|
||||
current_path = os.path.dirname(__file__)
|
||||
parent_path = os.path.abspath(os.path.join(current_path, os.path.pardir))
|
||||
paths = [current_path, parent_path]
|
||||
for path in paths:
|
||||
if path not in sys.path:
|
||||
sys.path.insert(0, path)
|
||||
|
||||
# more imports
|
||||
import database
|
||||
import processor
|
||||
from interface import api
|
||||
from interface import form
|
||||
|
||||
# configure logging
|
||||
def configure_logging(level):
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(level)
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(level)
|
||||
# create formatter
|
||||
formatter = logging.Formatter(
|
||||
'[%(asctime)s] %(name)s %(levelname)s %(message)s')
|
||||
# add formatter to ch
|
||||
ch.setFormatter(formatter)
|
||||
# add ch to logger
|
||||
root_logger.addHandler(ch)
|
||||
|
||||
logging_level = (20, 10)[config.general['debug']]
|
||||
configure_logging(logging_level)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Config(object):
|
||||
JOBS = [
|
||||
{
|
||||
'id': 'fetch_mail',
|
||||
'func': 'core.cron:fetch_mail_answers',
|
||||
'trigger': 'interval',
|
||||
'seconds': 120
|
||||
},
|
||||
{
|
||||
'id': 'submit_new_comment',
|
||||
'func': 'core.cron:submit_new_comment',
|
||||
'trigger': 'interval',
|
||||
'seconds': 60
|
||||
},
|
||||
]
|
||||
|
||||
# initialize database
|
||||
database.setup()
|
||||
|
||||
# start processor
|
||||
template_path = os.path.abspath(os.path.join(current_path, '../templates'))
|
||||
processor.start(template_path)
|
||||
|
||||
# cron
|
||||
app.config.from_object(Config())
|
||||
scheduler = APScheduler()
|
||||
scheduler.init_app(app)
|
||||
scheduler.start()
|
||||
|
||||
# tune logging level
|
||||
if not config.general['debug']:
|
||||
logging.getLogger('werkzeug').level = logging.WARNING
|
||||
|
||||
logger.info("Start Stacosys application")
|
||||
|
||||
app.run(host=config.http['host'],
|
||||
port=config.http['port'],
|
||||
debug=config.general['debug'], use_reloader=False)
|
||||
|
|
@ -3,26 +3,29 @@
|
|||
|
||||
import logging
|
||||
import time
|
||||
from core import app
|
||||
from core import processor
|
||||
from models.comment import Comment
|
||||
from core import mailer
|
||||
from core import templater
|
||||
from model.comment import Comment
|
||||
from model.comment import Site
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def fetch_mail_answers():
|
||||
|
||||
logger.info('DEBUT POP MAIL')
|
||||
logger.info("DEBUT POP MAIL")
|
||||
time.sleep(80)
|
||||
logger.info('FIN POP MAIL')
|
||||
#data = request.get_json()
|
||||
#logger.debug(data)
|
||||
logger.info("FIN POP MAIL")
|
||||
# data = request.get_json()
|
||||
# logger.debug(data)
|
||||
|
||||
# processor.enqueue({'request': 'new_mail', 'data': data})
|
||||
|
||||
#processor.enqueue({'request': 'new_mail', 'data': data})
|
||||
|
||||
def submit_new_comment():
|
||||
|
||||
for comment in Comment.select().where(Comment.notified.is_null()):
|
||||
# render email body template
|
||||
|
||||
comment_list = (
|
||||
"author: %s" % comment.author_name,
|
||||
"site: %s" % comment.author_site,
|
||||
|
|
@ -33,15 +36,10 @@ def submit_new_comment():
|
|||
"",
|
||||
)
|
||||
comment_text = "\n".join(comment_list)
|
||||
email_body = get_template("new_comment").render(url=url, comment=comment_text)
|
||||
email_body = templater.get_template("new_comment").render(url=comment.url, comment=comment_text)
|
||||
|
||||
if clientip:
|
||||
client_ips[comment.id] = clientip
|
||||
|
||||
# send email
|
||||
subject = "STACOSYS %s: [%d:%s]" % (site.name, comment.id, token)
|
||||
mailer.send_mail(site.admin_email, subject, email_body)
|
||||
logger.debug("new comment processed ")
|
||||
|
||||
def get_template(name):
|
||||
return env.get_template(config.general["lang"] + "/" + name + ".tpl")
|
||||
site = Site.select().where(Site.id == Comment.site).get()
|
||||
# send email
|
||||
subject = "STACOSYS %s: [%d:%s]" % (site.name, comment.id, site.token)
|
||||
mailer.send_mail(site.admin_email, subject, email_body)
|
||||
logger.debug("new comment processed ")
|
||||
|
|
|
|||
|
|
@ -2,26 +2,15 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
|
||||
from conf import config
|
||||
import functools
|
||||
from playhouse.db_url import connect
|
||||
|
||||
|
||||
def get_db():
|
||||
return connect(config.general['db_url'])
|
||||
return connect(config.get(config.DB_URL))
|
||||
|
||||
|
||||
def provide_db(func):
|
||||
def setup():
|
||||
from model.site import Site
|
||||
from model.comment import Comment
|
||||
|
||||
@functools.wraps(func)
|
||||
def new_function(*args, **kwargs):
|
||||
return func(get_db(), *args, **kwargs)
|
||||
|
||||
return new_function
|
||||
|
||||
|
||||
@provide_db
|
||||
def setup(db):
|
||||
from models.site import Site
|
||||
from models.comment import Comment
|
||||
|
||||
db.create_tables([Site, Comment], safe=True)
|
||||
get_db().create_tables([Site, Comment], safe=True)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@ import json
|
|||
from datetime import datetime
|
||||
from threading import Thread
|
||||
from queue import Queue
|
||||
from jinja2 import Environment
|
||||
from jinja2 import FileSystemLoader
|
||||
from models.site import Site
|
||||
from models.comment import Comment
|
||||
from model.site import Site
|
||||
from model.comment import Comment
|
||||
from helpers.hashing import md5
|
||||
from conf import config
|
||||
from core import mailer
|
||||
|
|
|
|||
16
app/core/templater.py
Normal file
16
app/core/templater.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
from jinja2 import Environment
|
||||
from jinja2 import FileSystemLoader
|
||||
from conf import config
|
||||
|
||||
current_path = os.path.dirname(__file__)
|
||||
template_path = os.path.abspath(os.path.join(current_path, "../templates"))
|
||||
env = Environment(loader=FileSystemLoader(template_path))
|
||||
|
||||
|
||||
def get_template(name):
|
||||
return env.get_template(config.general["lang"] + "/" + name + ".tpl")
|
||||
|
|
@ -6,7 +6,7 @@ from conf import config
|
|||
|
||||
|
||||
def salt(value):
|
||||
string = '%s%s' % (value, config.security['salt'])
|
||||
string = "%s%s" % (value, config.get(config.SECURITY_SALT))
|
||||
dk = hashlib.sha256(string.encode())
|
||||
return dk.hexdigest()
|
||||
|
||||
|
|
|
|||
0
app/interface/__init__.py
Normal file
0
app/interface/__init__.py
Normal file
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
import logging
|
||||
from flask import request, jsonify, abort
|
||||
from core import app
|
||||
from models.site import Site
|
||||
from models.comment import Comment
|
||||
from model.site import Site
|
||||
from model.comment import Comment
|
||||
from conf import config
|
||||
from core import processor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = config.flaskapp()
|
||||
|
||||
@app.route("/ping", methods=['GET'])
|
||||
def ping():
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@
|
|||
import logging
|
||||
from datetime import datetime
|
||||
from flask import request, abort, redirect
|
||||
from core import app
|
||||
from models.site import Site
|
||||
from models.comment import Comment
|
||||
from model.site import Site
|
||||
from model.comment import Comment
|
||||
from conf import config
|
||||
from helpers.hashing import md5
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = config.flaskapp()
|
||||
|
||||
@app.route("/newcomment", methods=["POST"])
|
||||
def new_form_comment():
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ from peewee import CharField
|
|||
from peewee import TextField
|
||||
from peewee import DateTimeField
|
||||
from peewee import ForeignKeyField
|
||||
from models.site import Site
|
||||
from model.site import Site
|
||||
from core.database import get_db
|
||||
|
||||
|
||||
94
app/run.py
94
app/run.py
|
|
@ -1,36 +1,90 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
from clize import Clize, run
|
||||
from jsonschema import validate
|
||||
from conf import config, schema
|
||||
from flask import Flask
|
||||
from flask_apscheduler import APScheduler
|
||||
from conf import config
|
||||
|
||||
# configure logging
|
||||
def configure_logging(level):
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(level)
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(level)
|
||||
# create formatter
|
||||
formatter = logging.Formatter("[%(asctime)s] %(name)s %(levelname)s %(message)s")
|
||||
# add formatter to ch
|
||||
ch.setFormatter(formatter)
|
||||
# add ch to logger
|
||||
root_logger.addHandler(ch)
|
||||
|
||||
|
||||
def load_json(filename):
|
||||
jsondoc = None
|
||||
with open(filename, 'rt') as json_file:
|
||||
jsondoc = json.loads(json_file.read())
|
||||
return jsondoc
|
||||
class JobConfig(object):
|
||||
|
||||
JOBS = []
|
||||
|
||||
def __init__(self, mail_polling_seconds, new_comment_polling_seconds):
|
||||
self.JOBS = [
|
||||
{
|
||||
"id": "fetch_mail",
|
||||
"func": "core.cron:fetch_mail_answers",
|
||||
"trigger": "interval",
|
||||
"seconds": mail_polling_seconds,
|
||||
},
|
||||
{
|
||||
"id": "submit_new_comment",
|
||||
"func": "core.cron:submit_new_comment",
|
||||
"trigger": "interval",
|
||||
"seconds": new_comment_polling_seconds,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@Clize
|
||||
def stacosys_server(config_pathname):
|
||||
|
||||
# load and validate startup config
|
||||
conf = load_json(config_pathname)
|
||||
json_schema = json.loads(schema.json_schema)
|
||||
validate(conf, json_schema)
|
||||
app = Flask(__name__)
|
||||
config.initialize(config_pathname, app)
|
||||
|
||||
# set configuration
|
||||
config.general = conf['general']
|
||||
config.http = conf['http']
|
||||
config.security = conf['security']
|
||||
config.rss = conf['rss']
|
||||
# configure logging
|
||||
logger = logging.getLogger(__name__)
|
||||
configure_logging(logging.INFO)
|
||||
logging.getLogger("werkzeug").level = logging.WARNING
|
||||
|
||||
# start application
|
||||
from core import app
|
||||
# initialize database
|
||||
from core import database
|
||||
|
||||
if __name__ == '__main__':
|
||||
database.setup()
|
||||
|
||||
# start processor
|
||||
from core import processor
|
||||
|
||||
# cron email fetcher
|
||||
app.config.from_object(
|
||||
JobConfig(
|
||||
config.getInt(config.MAIL_POLLING), config.getInt(config.COMMENT_POLLING)
|
||||
)
|
||||
)
|
||||
scheduler = APScheduler()
|
||||
scheduler.init_app(app)
|
||||
scheduler.start()
|
||||
|
||||
logger.info("Start Stacosys application")
|
||||
|
||||
# start Flask
|
||||
from interface import api
|
||||
from interface import form
|
||||
|
||||
app.run(
|
||||
host=config.get(config.HTTP_HOST),
|
||||
port=config.get(config.HTTP_PORT),
|
||||
debug=False,
|
||||
use_reloader=False,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run(stacosys_server)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue