From 7ba18be952dbe35f7d3a97e736cc00c388d73bae Mon Sep 17 00:00:00 2001 From: david Date: Tue, 22 Nov 2016 00:40:57 +0100 Subject: [PATCH] draft work --- factoriocp.conf.sample | 1 + factoriocp.py | 46 +++++++++++++-- static/favicon.ico | Bin 9662 -> 15086 bytes views/default.tpl | 131 ++++++++++++++++++++--------------------- views/footer.tpl | 17 ++++++ views/header.tpl | 31 ++++++++++ views/login.tpl | 15 +---- views/server.tpl | 98 ++++++++++++++++++++++++++++++ 8 files changed, 253 insertions(+), 86 deletions(-) create mode 100644 views/footer.tpl create mode 100644 views/header.tpl create mode 100644 views/server.tpl diff --git a/factoriocp.conf.sample b/factoriocp.conf.sample index c6fd02b..0ea2366 100644 --- a/factoriocp.conf.sample +++ b/factoriocp.conf.sample @@ -12,6 +12,7 @@ static_files=/path/to/static/files host=localhost port=8000 debug=True +fqdn=factorio.socialnerds.org [factorio] path=/path/to/factorio/servers diff --git a/factoriocp.py b/factoriocp.py index 28fc7e8..7894c25 100644 --- a/factoriocp.py +++ b/factoriocp.py @@ -41,15 +41,16 @@ def log_in(username, password): # get a list of server dicts def get_servers(): pass - return [{ "name": "Creative fun", "version": "0.14.20", "status": "online" }, - { "name": "Mad enemies", "version": "0.14.19", "status": "offline" }] + return [{ "name": "Creative fun", "version": "0.14.20", "status": "online", "port": "43564" }, + { "name": "Mad enemies", "version": "0.14.19", "status": "offline", "port": "65432" }, + { "name": "Mad enemies2", "version": "0.14.19", "status": "offline", "port": "65431" }] # routing # render main page @get('/') -def home(): +def view_home(): username = logged_in() message = request.get_cookie(config['DEFAULT']['cookie_name'] + "_message", secret=config['DEFAULT']['cookie_secret']) @@ -70,7 +71,7 @@ def home(): # get login credentials @post('/login') -def post_login(): +def login(): username = request.forms.get('username') password = request.forms.get('password') if log_in(username, password): @@ -90,7 +91,6 @@ def post_login(): # delete cookie @get('/logout') -@get('/logout/') def logout(): if logged_in(): response.delete_cookie(config['DEFAULT']['cookie_name']) @@ -108,6 +108,42 @@ def logout(): def send_static(filename): return static_file(filename, root=config['DEFAULT']['static_files']) +# render server page +@get('/server/') +def view_server(port): + username = logged_in() + message = request.get_cookie(config['DEFAULT']['cookie_name'] + "_message", + secret=config['DEFAULT']['cookie_secret']) + if username: + servers = get_servers() + server = [ server for server in servers if int(server['port']) == int(port) ] + if server: + return template('server', + app_name=config['DEFAULT']['app_name'], + server=server[0], + username=username, + fqdn=config['server']['fqdn'], + message=message) + else: + message = { "message": "Server does not exist", "alert": "danger" } + response.set_cookie(config['DEFAULT']['cookie_name'] + "_message", + message, + secret=config['DEFAULT']['cookie_secret'], + max_age=5, + path="/") + redirect("/") + else: + redirect("/") + + +# create new server +@get('/create') +def create_server(): + pass + + + + # run webserver if __name__ == "__main__": diff --git a/static/favicon.ico b/static/favicon.ico index d6bb62b6e73a9aa0dc3687f7faf9c5e521d727f8..6fd60a6d9c5ed549a914bd2274dd369357a2fb6e 100644 GIT binary patch literal 15086 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 VVL7pSx}V;OA9SrJkWk-={~u9Ys@(tp literal 9662 zcmeHLNoZ4H5dM=i2^cpJL=4)B23kR=AR=Pv)sr{Di&$?Wf`};MLMtluAT9^*9$Kv% zN-rX6DF`ZV2M>xUVl60E(L+JB#y-DE-;{Yn-q!pnTHb^&Gyg2#KbgF|CB~%iYHc-m zZ!&!)V-^}?ngO^>2SENrk_jXeNG6a>Aelfifyx9f;N1zpoJ!Wj8`(j*+eGekndbv~ z8bxfjXoPI?`F(~hBG;Ok&*y`Q*Qhi^l9Lb5B9+?C5y#=z%TzSV#G;%(;gm4r_;Re2?RPkLGMD&=aV;7S;_d0 zD)Fhh`cNpjHIIx9>Y!MU!RFi{_P4dQvB@#gJK1SLUjm2Z)|4`KM+e2aYX2fW$%Etj zr0~~j_JClLy9$|%O|}1ZYL7=)Uj%4&wV*eZO1)FuSbD@p|7*a=JmbPL*#yg{VOD2et$nj?bndnGUC(=_4OUN4*1Ce1Q==9a!+j^z;QXB@^P<3 zdLSfU*6*b{w{{-%jey!Wh~+5P#a!s9BKOp`zJIt4Qk~b0(QUT*zg# - - - - - - - - - +%include('header.tpl', app_name=app_name, message=message) + +
+ +

Control your Factorio game servers from here.

- {{ app_name }} - - - - - - - - - - -
-

- %if message: -

+ + + + + + + + + + + + %for server in servers: + %if server['status'] == "online": + + + + + + + + %else: + + + + + + + %end -

- - - -
-
-

{{ app_name }}

-
-

{{ username }} (logout)

-

This is your Factorio server control panel.

-

It is free software and its code is hosted here.

- - -

Servers

-
- %for server in servers: - %if server['status'] == "online": -

{{ server['name'] }} {{ server['status'] }}

- %else: -

{{ server['name'] }} {{ server['status'] }}

%end - Version: {{ server['version'] }} -

- %end -
- -
-
- factoriocp v0.1 -
-
- - - - - - - - - + +
NameVersionPortStatusActions
{{ server['name'] }}{{ server['version'] }}{{ server['port'] }}{{ server['status'] }} + Stop + Edit +
{{ server['name'] }}{{ server['version'] }}{{ server['port'] }}{{ server['status'] }} + Start + Delete + Edit +
+
+%include('footer.tpl', username=username) diff --git a/views/footer.tpl b/views/footer.tpl new file mode 100644 index 0000000..b9f15f9 --- /dev/null +++ b/views/footer.tpl @@ -0,0 +1,17 @@ +
+
+
+ factoriocp v0.1 +
+
+
+ + + + + + + + + diff --git a/views/header.tpl b/views/header.tpl new file mode 100644 index 0000000..75dabb8 --- /dev/null +++ b/views/header.tpl @@ -0,0 +1,31 @@ + + + + + + + + + + + + {{ app_name }} + + + + + + + + + +
+

+ %if message: +

+ %end +

+
diff --git a/views/login.tpl b/views/login.tpl index 568be9b..3cea904 100644 --- a/views/login.tpl +++ b/views/login.tpl @@ -20,15 +20,7 @@ -
- - %if message: - - %end -
+
- - - -
+
diff --git a/views/server.tpl b/views/server.tpl new file mode 100644 index 0000000..e9b9b27 --- /dev/null +++ b/views/server.tpl @@ -0,0 +1,98 @@ +%include('header.tpl', app_name=app_name, message=message) + +
+
+
+ %if server['status'] == "online": +

{{ server['name'] }}Online

+ %else: +

{{ server['name'] }}Offline

+ %end +
+
+
+ + +
+
+
+

Some fon server description goes here.

+ + + + + + + + %if server['status'] == "online": + + + + + + %else: + + + + + + %end +
AddressVersionActions
{{ fqdn }}:{{ server['port'] }}{{ server['version'] }} + Stop +
{{ fqdn }}:{{ server['port'] }}{{ server['version'] }} + Start + Delete +
+ +

+

Settings

+
+
+ +
+

+ +

+

Backups

+
+
+ +
+

+ +

+

Mods

+
+
+ +
+

+ +

+

Screenshots

+
+
+ +
+

+ +

+

Console

+
+
+ +
+

+ + +
+%include('footer.tpl', username=username)