2025-05-08 16:12:33 +12:00
|
|
|
import cherrypy
|
|
|
|
|
from sqlalchemy import create_engine
|
|
|
|
|
from accounting.models import Base
|
|
|
|
|
from accounting.api import AccountingAPI
|
|
|
|
|
import os
|
2025-05-08 22:41:14 +12:00
|
|
|
import json
|
2025-05-08 16:12:33 +12:00
|
|
|
from config import DATABASE_URI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def CORS():
|
|
|
|
|
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
|
|
|
|
|
cherrypy.response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
|
|
|
|
|
cherrypy.response.headers["Access-Control-Allow-Headers"] = "Content-Type"
|
|
|
|
|
|
|
|
|
|
|
2025-05-08 22:41:14 +12:00
|
|
|
# JSON Tools for response serialization
|
|
|
|
|
class JSONEncoder(object):
|
|
|
|
|
def __init__(self):
|
|
|
|
|
self.json_encoder = json.JSONEncoder()
|
|
|
|
|
|
|
|
|
|
def __call__(self, value):
|
|
|
|
|
# Convert the Python object to a JSON string then to bytes
|
|
|
|
|
return json.dumps(value).encode('utf-8')
|
|
|
|
|
|
|
|
|
|
|
2025-05-08 16:12:33 +12:00
|
|
|
class Root:
|
|
|
|
|
@cherrypy.expose
|
|
|
|
|
def index(self):
|
|
|
|
|
return open(os.path.join(os.path.dirname(__file__), 'accounting/templates/index.html')).read()
|
|
|
|
|
|
|
|
|
|
@cherrypy.expose
|
|
|
|
|
def favicon_ico(self):
|
|
|
|
|
return cherrypy.lib.static.serve_file(
|
|
|
|
|
os.path.join(os.path.dirname(__file__), 'static/favicon.ico'),
|
|
|
|
|
content_type='image/x-icon'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setup_database():
|
|
|
|
|
engine = create_engine(DATABASE_URI)
|
|
|
|
|
Base.metadata.create_all(engine)
|
|
|
|
|
return engine
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
# Database setup
|
|
|
|
|
db_engine = setup_database()
|
|
|
|
|
|
|
|
|
|
# Create static directory if it doesn't exist
|
|
|
|
|
static_path = os.path.join(os.path.dirname(__file__), 'static')
|
|
|
|
|
if not os.path.exists(static_path):
|
|
|
|
|
os.makedirs(static_path)
|
|
|
|
|
|
2025-05-08 22:41:14 +12:00
|
|
|
# Register tools
|
|
|
|
|
cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
|
|
|
|
|
|
|
|
|
|
# Root application config
|
|
|
|
|
root_conf = {
|
2025-05-08 16:12:33 +12:00
|
|
|
'/': {
|
|
|
|
|
'tools.sessions.on': True,
|
|
|
|
|
'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)),
|
|
|
|
|
'tools.CORS.on': True
|
|
|
|
|
},
|
|
|
|
|
'/static': {
|
|
|
|
|
'tools.staticdir.on': True,
|
|
|
|
|
'tools.staticdir.dir': 'static',
|
2025-05-08 22:41:14 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# API application config
|
|
|
|
|
api_conf = {
|
|
|
|
|
'/': {
|
2025-05-08 16:12:33 +12:00
|
|
|
'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
|
|
|
|
|
'tools.CORS.on': True,
|
2025-05-08 22:41:14 +12:00
|
|
|
'tools.json_out.on': True, # Use the built-in JSON serializer
|
|
|
|
|
'tools.encode.on': True,
|
|
|
|
|
'tools.encode.encoding': 'utf-8',
|
|
|
|
|
# Process JSON request bodies
|
|
|
|
|
'request.body.processors': {
|
|
|
|
|
'application/json': cherrypy.lib.jsontools.json_processor
|
|
|
|
|
}
|
2025-05-08 16:12:33 +12:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-08 22:41:14 +12:00
|
|
|
# Create and mount Root application
|
2025-05-08 16:12:33 +12:00
|
|
|
root = Root()
|
2025-05-08 22:41:14 +12:00
|
|
|
cherrypy.tree.mount(root, '/', root_conf)
|
2025-05-08 16:12:33 +12:00
|
|
|
|
2025-05-08 22:41:14 +12:00
|
|
|
# Create and mount API as a separate application
|
|
|
|
|
api = AccountingAPI(db_engine)
|
|
|
|
|
cherrypy.tree.mount(api, '/api', api_conf)
|
2025-05-08 16:12:33 +12:00
|
|
|
|
|
|
|
|
# Start server
|
|
|
|
|
cherrypy.config.update({
|
|
|
|
|
'server.socket_host': '0.0.0.0',
|
|
|
|
|
'server.socket_port': 8080,
|
|
|
|
|
'log.screen': True,
|
|
|
|
|
'engine.autoreload.on': True
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
print("Starting accounting system...")
|
|
|
|
|
cherrypy.engine.start()
|
|
|
|
|
cherrypy.engine.block()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2025-05-08 22:41:14 +12:00
|
|
|
main()
|