19 |
20 |
21 |
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import os.path
4 | import sqlite3
5 |
6 | from flask import Flask
7 |
8 | from admincraft import config
9 | from admincraft import views
10 |
11 | app = Flask(__name__)
12 |
13 | #Registering view module
14 | app.register_blueprint(views.admincraft)
15 | print app.url_map
16 |
17 | #Setting session key from config
18 | app.secret_key = config.SECRETKEY
19 |
20 | #Create database if it does not exist
21 | dbpath = config.DATABASE
22 |
23 | if not os.path.exists(dbpath):
24 | conn = sqlite3.connect(dbpath)
25 | c = conn.cursor()
26 | c.execute('''create table tasks (type text, month text, day text, hour text, minute text)''')
27 | conn.commit()
28 | c.close()
29 |
30 | if __name__ == "__main__":
31 | #Start App
32 | app.run(host=config.SERVERHOST, port=config.SERVERPORT, debug=config.DEBUGMODE, use_reloader=config.AUTORELOADER)
33 |
--------------------------------------------------------------------------------
/MIT-LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2013 Alfred Gutierrez
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/admincraft/config.py:
--------------------------------------------------------------------------------
1 | # config.py reads config.ini and sets variable. This file does not need to be modified.
2 |
3 | import os
4 | import sys
5 | from ConfigParser import SafeConfigParser
6 |
7 | path = os.path.split(sys.argv[0])[0]
8 |
9 | config = SafeConfigParser()
10 | config.read('config.ini')
11 | print path
12 |
13 | # Main options required.
14 | USERNAME = config.get('global', 'USERNAME')
15 | PASSWORD = config.get('global', 'PASSWORD')
16 | MINECRAFTDIR = config.get('global', 'MINECRAFTDIR')
17 | SERVERHOST = config.get('global', 'SERVERHOST')
18 | SERVERPORT = config.getint('global', 'SERVERPORT')
19 | SECRETKEY = config.get('global', 'SECRETKEY')
20 | BACKUPDIR = config.get('global', 'BACKUPDIR')
21 |
22 | # Extra options, but not required.
23 | THEME = config.get('global', 'THEME')
24 | LOGINTERVAL = config.getint('global', 'LOGINTERVAL')
25 | LOGLINES = config.getint('global', 'LOGLINES')
26 | MINECRAFTDAEMON = config.get('global', 'MINECRAFTDAEMON')
27 | DATABASE = config.get('global', 'DATABASE')
28 |
29 | # Default Minecraft Config files.
30 | SERVERLOG = config.get('global', 'SERVERLOG')
31 | SERVERPROPERTIES = config.get('global', 'SERVERPROPERTIES')
32 | SERVEROPS = config.get('global', 'SERVEROPS')
33 | WHITELIST = config.get('global', 'WHITELIST')
34 | BANNEDPLAYERS = config.get('global', 'BANNEDPLAYERS')
35 | BANNEDIPS = config.get('global', 'BANNEDIPS')
36 |
37 | AUTORELOADER = config.getboolean('global', 'AUTORELOADER')
38 | DEBUGMODE = config.getboolean('global', 'DEBUGMODE')
39 |
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | [global]
2 |
3 | ###############################
4 | #Global Configuration Settings#
5 | ###############################
6 |
7 | # Main options required. Configure these.
8 | USERNAME = admin ; Username required to log into AdminCraft
9 | PASSWORD = password ; Password required to log into AdminCraft
10 | MINECRAFTDIR = /path/to/minecraft-server/ ; Location of Minecraft Server Directory. Requires trailing slash.
11 | SERVERHOST = 0.0.0.0 ; Bind to a specific IP. 0.0.0.0 as default.
12 | SERVERPORT = 5000 ; AdminCraft server port.
13 | SECRETKEY = supersecret ; Change this to something random.
14 | BACKUPDIR = /path/to/backup/dir ; Location of Backup Directory. Requires trailing slash.
15 |
16 | # Extra options, but not required.
17 | THEME = default ; Configure interface theme.
18 | LOGINTERVAL = 5000 ; How often to refresh the console log. 1000 = 1s.
19 | LOGLINES = 30 ; How many lines to display at a time.
20 | MINECRAFTDAEMON = /etc/init.d/minecraft ; Location of Minecraft daemon script.
21 | DATABASE = admincraft.db ; Location of AdminCraft Database.
22 |
23 | # Default Minecraft Config files. Only change if you know what you are doing.
24 | SERVERLOG = server.log
25 | SERVERPROPERTIES = server.properties
26 | SERVEROPS = ops.txt
27 | WHITELIST = white-list.txt
28 | BANNEDPLAYERS = banned-players.txt
29 | BANNEDIPS = banned-ips.txt
30 |
31 | # Development options
32 | AUTORELOADER = False
33 | DEBUGMODE = False
34 |
--------------------------------------------------------------------------------
/static/themes/minimal/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-image: url(images/background.png);
3 | background-repeat: repeat;
4 | }
5 |
6 | input {
7 | border-radius: 4px;
8 | border: none;
9 | background-color: rgb( 255, 255, 255 );
10 | width: 278px;
11 | height: 42px;
12 | z-index: 5;
13 | font-family: "Helvetica Neue",Helvetica,sans-serif;
14 | font-size: 16px;
15 | color: #adadad;
16 | font-weight: 400;
17 | padding-left: 10px;
18 | outline: none;
19 | margin-top: 0px;
20 | padding-bottom: 0px;
21 | padding-top: 0px;
22 | }
23 | form {
24 | width: 290px;
25 | }
26 |
27 | #horizon {
28 | color: white;
29 | background-color: transparent;
30 | text-align: center;
31 | position: absolute;
32 | top: 50%;
33 | left: 0px;
34 | width: 100%;
35 | height: 1px;
36 | overflow: visible;
37 | visibility: visible;
38 | display: block
39 | }
40 |
41 | #content {
42 | background-color: transparent;
43 | margin-left: -150px;
44 | position: absolute;
45 | top: -125px;
46 | left: 50%;
47 | width: 250px;
48 | height: 70px;
49 | visibility: visible
50 | }
51 |
52 | input#user {
53 | border-bottom-left-radius: 0px;
54 | border-bottom-right-radius: 0px;
55 | }
56 |
57 |
58 |
59 | input#pass {
60 | border-top-left-radius: 0px;
61 | border-top-right-radius: 0px;
62 | margin-top: 1px;
63 | }
64 |
65 | input#login {
66 | margin-top: 10px;
67 | }
68 |
69 | h2 {
70 | font-family: "Helvetica Neue",Helvetica,sans-serif;
71 | color: #5c5e5e;
72 | font-weight: 300;
73 | text-rendering: optimizeLegibility;
74 | }
75 |
76 | input#login {
77 | width: 70px;
78 | height: 30px;
79 | float: right;
80 | background-color: rgba(79,222,40,0.5);
81 | color: #fff;
82 | }
83 |
84 | input#login:hover {
85 | background-color: rgba(79,222,40,0.8);
86 | }
87 |
--------------------------------------------------------------------------------
/static/themes/default/dataValues.css:
--------------------------------------------------------------------------------
1 | #dataValuesWindow {
2 |
3 | width: 600px;
4 | background: #ccc;
5 | border-style: solid;
6 | border-width: 1px;
7 | border-color: #a7a7a7;
8 | padding: 5px;
9 |
10 | -moz-border-radius: 15px;
11 | border-radius: 15px;
12 |
13 | }
14 |
15 |
16 | ul.dataTabs {
17 | margin: 0;
18 | padding: 0;
19 | float: left;
20 | list-style: none;
21 | height: 26px; /*--Set height of tabs--*/
22 | border-top: 1px solid #999;
23 | border-left: 1px solid #999;
24 | width: 100%;
25 | }
26 | ul.dataTabs li {
27 | float: left;
28 | margin: 0;
29 | padding: 0;
30 | height: 25px; /*--Subtract 1px from the height of the unordered list--*/
31 | line-height: 24px; /*--Vertically aligns the text within the tab--*/
32 | border: 1px solid #999;
33 | border-left: none;
34 | margin-top: -1px; /*--Pull the list item down 1px--*/
35 | overflow: hidden;
36 | position: relative;
37 | background: #e0e0e0;
38 | }
39 | ul.dataTabs li a {
40 | text-decoration: none;
41 | color: #000;
42 | display: block;
43 | font-size: 11px;
44 | padding: 0 20px;
45 | border: 1px solid #eee; /*--Gives the bevel look with a 1px white border inside the list item--*/
46 | outline: none;
47 |
48 | }
49 | ul.dataTabs li a:hover {
50 | background: #ccc;
51 | }
52 | html ul.dataTabs li.active, html ul.dataTabs li.active a:hover { /*--Makes sure that the active tab does not listen to the hover properties--*/
53 | background: #eee;
54 | border-top: 1px solid #eee; /*--Makes the active tab look like it's connected with its content--*/
55 | }
56 |
57 | /* Right Tab Content */
58 |
59 | .dataTab_container {
60 | border: 1px solid #999;
61 | border-bottom: none;
62 | overflow: hidden;
63 | clear: both;
64 | float: left; width: 100%;
65 | background: #eee;
66 | margin-left: auto;
67 | margin-right: auto;
68 | }
69 | .dataTab_content {
70 | margin-left: 5px;
71 | margin-right: auto;
72 | padding: 5px;
73 | font-size: 11px;
74 | }
75 |
--------------------------------------------------------------------------------
/static/themes/minimal/dataValues.css:
--------------------------------------------------------------------------------
1 | #dataValuesWindow {
2 |
3 | width: 600px;
4 | background: #ccc;
5 | border-style: solid;
6 | border-width: 1px;
7 | border-color: #a7a7a7;
8 | padding: 5px;
9 |
10 | -moz-border-radius: 15px;
11 | border-radius: 15px;
12 |
13 | }
14 |
15 |
16 | ul.dataTabs {
17 | margin: 0;
18 | padding: 0;
19 | float: left;
20 | list-style: none;
21 | height: 26px; /*--Set height of tabs--*/
22 | border-top: 1px solid #999;
23 | border-left: 1px solid #999;
24 | width: 100%;
25 | }
26 | ul.dataTabs li {
27 | float: left;
28 | margin: 0;
29 | padding: 0;
30 | height: 25px; /*--Subtract 1px from the height of the unordered list--*/
31 | line-height: 24px; /*--Vertically aligns the text within the tab--*/
32 | border: 1px solid #999;
33 | border-left: none;
34 | margin-top: -1px; /*--Pull the list item down 1px--*/
35 | overflow: hidden;
36 | position: relative;
37 | background: #e0e0e0;
38 | }
39 | ul.dataTabs li a {
40 | text-decoration: none;
41 | color: #000;
42 | display: block;
43 | font-size: 11px;
44 | padding: 0 20px;
45 | border: 1px solid #eee; /*--Gives the bevel look with a 1px white border inside the list item--*/
46 | outline: none;
47 |
48 | }
49 | ul.dataTabs li a:hover {
50 | background: #ccc;
51 | }
52 | html ul.dataTabs li.active, html ul.dataTabs li.active a:hover { /*--Makes sure that the active tab does not listen to the hover properties--*/
53 | background: #eee;
54 | border-top: 1px solid #eee; /*--Makes the active tab look like it's connected with its content--*/
55 | }
56 |
57 | /* Right Tab Content */
58 |
59 | .dataTab_container {
60 | border: 1px solid #999;
61 | border-bottom: none;
62 | overflow: hidden;
63 | clear: both;
64 | float: left; width: 100%;
65 | background: #eee;
66 | margin-left: auto;
67 | margin-right: auto;
68 | }
69 | .dataTab_content {
70 | margin-left: 5px;
71 | margin-right: auto;
72 | padding: 5px;
73 | font-size: 11px;
74 | }
75 |
--------------------------------------------------------------------------------
/admincraft/templates/themes/default/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AdminCraft v0.3
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | AdminCraft Login
23 |
29 |
30 |
31 |
32 |
33 |
34 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/admincraft/tasks.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | # runBackup.py is imported by runserver.py. This module runs the
4 | # backup commands on a scheduled basis. Configured in config.ini.
5 | import sqlite3
6 | import shutil
7 | import tarfile
8 | import datetime
9 |
10 | from flask import Markup
11 |
12 | from apscheduler.scheduler import Scheduler
13 | from time import sleep
14 |
15 | import config
16 |
17 |
18 | #Initialize and start the Scheduler
19 | sched = Scheduler(daemon=False)
20 |
21 | # Called as a GET/POST request from views to start or stop the daemons.
22 | def startTaskDaemon():
23 | if sched.get_jobs() == []:
24 | print "Starting Task daemon..."
25 | sched.start()
26 | createJobs()
27 | else:
28 | print "Job already running!"
29 | print sched.get_jobs()
30 |
31 | def stopTaskDaemon():
32 | try:
33 | print "Shutting down Task daemon..."
34 | sched.shutdown(wait=False, shutdown_threadpool=False)
35 | sched.unschedule_func(runBackupJobs)
36 | print sched.print_jobs()
37 | except:
38 | print "Tasks not started!"
39 |
40 | def checkStatus():
41 | if sched.get_jobs() == []:
42 | print "Offline"
43 | status = Markup('Task Scheduler is Offline')
44 |
45 | else:
46 | print "Online"
47 | status = Markup('Task Scheduler is Online')
48 | return status
49 |
50 |
51 | def createJobs():
52 |
53 | dbpath = config.DATABASE
54 |
55 | conn = sqlite3.connect(dbpath)
56 | c = conn.cursor()
57 | c.execute('''SELECT * FROM tasks''')
58 | print c
59 |
60 | for task, dom, dow, hour, minute in c:
61 | if "all" in dom:
62 | dom = dom.replace("all", "*")
63 | if "all" in dow:
64 | dow = dow.replace("all", "*")
65 | if "all" in hour:
66 | hour = hour.replace("all", "*")
67 | if "all" in minute:
68 | minute = minute.replace("all", "*")
69 |
70 | print task, dom, dow, hour, minute
71 | sched.add_cron_job(runBackupJobs, day=dom, day_of_week=dow, hour=hour, minute=minute)
72 |
73 | c.close()
74 |
75 | # All Cron Jobs go here.
76 |
77 | # Backup task to copytree of source to backup destination,
78 | # tars the directory, then removes the copied directory.
79 | def runBackupJobs():
80 |
81 | print "Running backup..."
82 | src = config.MINECRAFTDIR + "world"
83 | dst = config.BACKUPDIR + "world"
84 |
85 | print "Copying file to backup source..."
86 | shutil.copytree(src, dst)
87 |
88 | print "File copy completed"
89 | print "Tarballing files"
90 |
91 | now = datetime.datetime.now()
92 | filedate = now.strftime("%Y.%m.%d_%H.%M")
93 | print filedate
94 |
95 | tar = tarfile.open(dst + "_" + filedate + ".tar.gz", "w:gz")
96 |
97 | tar.add(dst, arcname="world")
98 | tar.close()
99 | print "File zipped"
100 |
101 | print "Removing copied files..."
102 | shutil.rmtree(dst)
103 | print dst + " directory removed"
104 |
105 | return "Archive Completed"
106 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AdminCraft #
2 |
3 | ##### This project has discontinued. Install at your own risk. Check out the list of other Minecraft server wrappers and admin consoles here: http://minecraft.gamepedia.com/Programs_and_editors/Server_wrappers
4 |
5 |
6 | AdminCraft is an open source Administration Web GUI Console for administering a
7 | Linux Minecraft Server. Admincraft is still in early development.
8 |
9 | AdminCraft provides the following features:
10 |
11 | - Start, stop and restart a Minecraft server
12 | - Create backups of worlds to a separate location or a mounted filesystem
13 | - Web Console to monitor server logs
14 | - Username/Password protected
15 | - Ability to chat with users or send custom commands
16 | - Built-in reference for Block/Item Dec codes
17 | - Configure server properties via Web GUI
18 | - Server Status (Online/Offline/Restarting/Backing Up/Viewing Logs)
19 | - View and configure user status (Connected players, Operators, Banned IPs or Players)
20 | - Ability to schedule 'cron-like' backup jobs on set intervals
21 |
22 | 
23 |
24 | #### TODO ####
25 |
26 | - Reworking item/block ID reference
27 | - Login sessions, security and support for multiple Admin Users
28 | - Support for viewing Log History (done)
29 | - Support to deploy and administer multiple instances of Minecraft Servers
30 | - Support to deploy AdminCraft on a separate server than the Minecraft Server
31 | - More server and Minecraft monitoring features
32 |
33 | ## Requirements ##
34 |
35 | - Minecraft Server 1.6.2+
36 | - A Linux OS. AdminCraft has only been tested on Ubuntu 11.04,
37 | but should be compatible with at least Ubuntu 9.04+
38 | - Python 2.6+. Python 3 is not yet supported
39 | - Python dependencies: Flask Framework 0.8
40 | - Enough server power to run a Minecraft Server. Basically at least
41 | a P4 with a minimum of 2GB of RAM. Minecraft likes to eat memory. :)
42 | - Basic Linux knowledge. :)
43 |
44 | ## Installation (Ubuntu 9.04+) ##
45 |
46 | Assuming you have at least Python 2.6+ installed and the minecraft_server.jar
47 | downloaded, please follow the steps below:
48 |
49 | 1. If not installed already, please install sqlite3 and python-setuptools:
50 |
51 | $ sudo apt-get install sqlite3 python-setuptools
52 |
53 | 2. Clone AdminCraft.git:
54 |
55 | $ git clone git://github.com/alfg/AdminCraft.git
56 |
57 | 3. Run setup.py to install dependencies:
58 |
59 | $ python setup.py install
60 |
61 | 4. Open config.ini and set the required variables.
62 |
63 | 5. Copy the Minecraft daemon to /etc/init.d/
64 |
65 | $ sudo cp scripts/minecraft /etc/init.d/
66 |
67 | 6. Configure USERNAME, WORLD, MCPATH, BACKUPPATH in
68 | /etc/init.d/minecraft in the text editor of your choice
69 |
70 | $ sudo vim /etc/init.d/minecraft
71 |
72 | 7. Set required permissions to the Minecraft daemon:
73 |
74 | $ sudo chmod a+x /etc/init.d/minecraft
75 |
76 | 8. Run update-rc.d to create sym links:
77 |
78 | $ sudo update-rc.d minecraft defaults
79 |
80 | 9. Now finally, run run.py:
81 |
82 | $ python run.py
83 |
84 | Or to run in the background:
85 |
86 | $ nohup python run.py &
87 |
88 | If you wish to view the nohup output:
89 |
90 | $ tail -f nohup.out
91 |
92 | 10. Using your preferred web browser, open 0.0.0.0:5000 (or your server's hostname:5000)
93 |
94 | 11. Great success! (I hope)
95 |
96 |
97 | ## Notes ##
98 |
99 | AdminCraft runs under Flask's built-in server with debugging and auto-reloading disabled by default. You can turn this on by changing DEBUGMODE and AUTORELOADER to "True" in config.ini. It is recommended to disable debugging if deploying to an externally accessible server.
100 |
--------------------------------------------------------------------------------
/admincraft/templates/themes/minimal/commandList.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ban <playername> Blacklists the name playername from the server so that they can no longer connect. Note: Bans supersede any whitelisting in place.
8 |
9 |
10 | ban-ip <ip-address> Blacklists an IP address so that all subsequent connections from it are rejected.
11 |
12 |
13 | banlist [ips] Displays the banlist. To display banned IP addresses, use the command banlistips
14 |
19 | gamemode <playername> <0|1> Remember, this will only affect playername and no one else; it may confuse others. Note:Player must currently be online for the command to work.
20 |
21 |
22 | give <playername> <data-value> [amount] [damage-value] Spawns amount (defaults to 1) of the item defined by data-value with the specified damage-value (defaults to 0) at playername's location. For example typing give John 4 30 will give a player called John 30 blocks of cobblestone.
23 |
24 |
25 | help OR ? Shows a list of availible server commands. Note banlist, whitelist, toggleddownfall, xp, tell, me and kill commands are not listed.
26 |
27 |
28 | kick <playername> Forcibly disconnects playername from the server.
29 |
30 |
31 | list Shows the names of all currently-connected players.
32 |
33 |
34 | pardon <playername> Removes playername from the blacklist, allowing them to connect again.
35 |
36 |
37 | pardon-ip <ip-address> Removes ip-address from the blacklist, allowing them to connect again.
38 |
39 |
40 | save-all Forces the server to write all pending changes to the world to disk.
41 |
42 |
43 | save-off Disables the server writing to the world files. All changes will temporarily be queued.
44 |
45 |
46 | save-on Enables the server writing to the world files. This is the default behaviour.
47 |
48 |
49 | say <message> Broadcasts message to all players on the server (in bright pink letters).
50 |
51 |
52 | stop Gracefully shuts down the server.
53 |
54 |
55 | time <set|add> <number> Set or increment (add to) the world time. <number> is an integer between 0 and 24000, inclusive, where 0 is dawn, 6000 midday, 12000 dusk and 18000 midnight (i.e. the clock is bisected; left side is night, right side is day). Note:You can also subtract from the current time by using the 'add X' modifier, by using a negative value (i.e. 'time add -6000' would change midnight to dusk)
56 |
64 | whitelist <add|remove> <playername> Adds or removes playername from whitelist.
65 |
66 |
67 | whitelist <on|off> Enables/disables the server's use of a whitelist. Note: Server ops will always be able to connect when the whitelist is active, even if their names do not appear in the whitelist.
68 |
69 |
70 | whitelist <reload> Reloads the list of playernames in white-list.txt from disk (used when whitelist.txt has been modified outside of Minecraft).
71 |
72 |
73 | xpset <playername> <amount> Gives the specified user the given number of orbs. Maximum is 5000 per command. Negative amounts may be used to remove experience progress, but not actual levels.
74 |
4 | ban <playername> Blacklists the name playername from the server so that they can no longer connect. Note: Bans supersede any whitelisting in place.
5 |
6 |
7 | ban-ip <ip-address> Blacklists an IP address so that all subsequent connections from it are rejected.
8 |
9 |
10 | banlist [ips] Displays the banlist. To display banned IP addresses, use the command banlistips
11 |
16 | gamemode <playername> <0|1> Remember, this will only affect playername and no one else; it may confuse others. Note:Player must currently be online for the command to work.
17 |
18 |
19 | give <playername> <data-value> [amount] [damage-value] Spawns amount (defaults to 1) of the item defined by data-value with the specified damage-value (defaults to 0) at playername's location. For example typing give John 4 30 will give a player called John 30 blocks of cobblestone.
20 |
21 |
22 | help OR ? Shows a list of availible server commands. Note banlist, whitelist, toggleddownfall, xp, tell, me and kill commands are not listed.
23 |
24 |
25 | kick <playername> Forcibly disconnects playername from the server.
26 |
27 |
28 | list Shows the names of all currently-connected players.
29 |
30 |
31 | pardon <playername> Removes playername from the blacklist, allowing them to connect again.
32 |
33 |
34 | pardon-ip <ip-address> Removes ip-address from the blacklist, allowing them to connect again.
35 |
36 |
37 | save-all Forces the server to write all pending changes to the world to disk.
38 |
39 |
40 | save-off Disables the server writing to the world files. All changes will temporarily be queued.
41 |
42 |
43 | save-on Enables the server writing to the world files. This is the default behaviour.
44 |
45 |
46 | say <message> Broadcasts message to all players on the server (in bright pink letters).
47 |
48 |
49 | stop Gracefully shuts down the server.
50 |
51 |
52 | time <set|add> <number> Set or increment (add to) the world time. <number> is an integer between 0 and 24000, inclusive, where 0 is dawn, 6000 midday, 12000 dusk and 18000 midnight (i.e. the clock is bisected; left side is night, right side is day). Note:You can also subtract from the current time by using the 'add X' modifier, by using a negative value (i.e. 'time add -6000' would change midnight to dusk)
53 |
61 | whitelist <add|remove> <playername> Adds or removes playername from whitelist.
62 |
63 |
64 | whitelist <on|off> Enables/disables the server's use of a whitelist. Note: Server ops will always be able to connect when the whitelist is active, even if their names do not appear in the whitelist.
65 |
66 |
67 | whitelist <reload> Reloads the list of playernames in white-list.txt from disk (used when whitelist.txt has been modified outside of Minecraft).
68 |
69 |
70 | xpset <playername> <amount> Gives the specified user the given number of orbs. Maximum is 5000 per command. Negative amounts may be used to remove experience progress, but not actual levels.
71 |
')
86 | else:
87 | serverStatus = "Unable to check server status."
88 |
89 | selectedTheme = 'themes/%s/index.html' % config.THEME
90 |
91 | return render_template(selectedTheme,username=username,
92 | name=name,
93 | ops=ops,
94 | logging=logging,
95 | whiteListUsers=whiteListUsers,
96 | bannedIPs=bannedIPs,
97 | properties=properties,
98 | serverStatus=serverStatus,
99 | LOGINTERVAL=config.LOGINTERVAL,
100 | THEME=config.THEME)
101 |
102 |
103 | #/server is used to send GET requests to Restart, Start, Stop or Backup server.
104 | @admincraft.route("/server", methods=['GET'])
105 | @requires_auth
106 | def serverState():
107 |
108 | #Grab option value from GET request.
109 | keyword = request.args.get('option')
110 |
111 | #Check status value and run /etc/init.d/minecraft command to restart/start/stop/backup.
112 | if keyword == "restart":
113 | subprocess.Popen(config.MINECRAFTDAEMON + ' restart', shell=True)
114 | return 'Restarting Minecraft Server...'
115 | elif keyword == "start":
116 | subprocess.Popen(config.MINECRAFTDAEMON + ' start', shell=True)
117 | return 'Starting Minecraft Server...'
118 | elif keyword == "stop":
119 | subprocess.Popen(config.MINECRAFTDAEMON + ' stop', shell=True)
120 | return 'Stopping Minecraft Server...'
121 | elif keyword == "backup":
122 | subprocess.Popen(config.MINECRAFTDAEMON + ' backup', shell=True)
123 | return 'Backing up Minecraft Server...'
124 |
125 | #If option value is 'status', then capture output and return 'Server is Online' or 'Server is Offline'
126 | elif keyword == "status":
127 | stdout = subprocess.Popen([config.MINECRAFTDAEMON + " status"], stdout=subprocess.PIPE, shell=True).communicate()[0]
128 | serverStatus = stdout
129 | if "online" in serverStatus:
130 | serverStatus = Markup('Server is Online')
131 |
132 | elif "offline" in serverStatus:
133 | serverStatus = Markup('Server is Offline')
134 | else:
135 | serverStatus = "Unable to check server status."
136 | return serverStatus
137 | else:
138 | return 'Invalid option!'
139 |
140 | #/logs returns the *entire* server log.
141 | @admincraft.route("/logs", methods=['GET'])
142 | @requires_auth
143 | def showLog():
144 | loggingFile = config.MINECRAFTDIR + config.SERVERLOG
145 | loggingFile = open(loggingFile, "r")
146 | loggingHTML = loggingFile.readlines()
147 |
148 | selectedTheme = 'themes/%s/logging.html' % config.THEME
149 | return render_template(selectedTheme, loggingHTML=loggingHTML)
150 |
151 |
152 | #/command is used when sending commands to '/etc/init.d/minecraft command' from the GUI. Used on mainConsole on index.html.
153 | @admincraft.route("/command", methods=['GET'])
154 | @requires_auth
155 | def sendCommand():
156 | #server.log file for logging command entered
157 | loggingFile = config.MINECRAFTDIR + config.SERVERLOG
158 | now = datetime.datetime.now()
159 | time = now.strftime("%Y-%m-%d %H:%M:%S")
160 |
161 | #Grabs operater value from GET request. say/give/command
162 | consoleOperator = str(request.args.get('operator'))
163 |
164 | #If the value was "command", then set as '' to remove redundancies when Popen is executed below.
165 | if consoleOperator == "command":
166 | consoleOperator = ''
167 | #Otherwise, keep the value. (say/give)
168 | else:
169 | consoleOperator = consoleOperator + ' '
170 |
171 |
172 | #Grab value from command GET request. This was entered via user from textInput box.
173 | command = str(request.args.get('command'))
174 |
175 | #Initiate full command via Popen. Return "Sending Command..."
176 | commandProc = config.MINECRAFTDAEMON + ' command "' + consoleOperator + command + '"'
177 | subprocess.Popen(commandProc, shell=True)
178 | print commandProc
179 |
180 | # Post Minecraft 1.3, Console logging was removed, so appending command entered to file manually.
181 | """ seems like console logging is back as of 1.4.7
182 | with open(loggingFile, "a") as f:
183 | f.write(time + " [CONSOLE] " + command + "\n")
184 | """
185 | return 'Sending Command...'
186 |
187 | #/logging reads the last X amount of lines from server.log to be parsed out on GUI #mainConsole.
188 | @admincraft.route("/logging", methods=['GET'])
189 | @requires_auth
190 | def logs():
191 |
192 | #Open and read last 40 lines. This needs to be configurable eventually.
193 | loggingFile = config.MINECRAFTDIR + config.SERVERLOG
194 | loggingFile = open(loggingFile, "r")
195 | loggingHTML = loggingFile.readlines()[-config.LOGLINES:]
196 |
197 | selectedTheme = 'themes/%s/logging.html' % config.THEME
198 | return render_template(selectedTheme, loggingHTML=loggingHTML)
199 |
200 | #/dataValues is used to create a dataIcons.html view, which is then imported to Index. Used for "Give" on GUI.
201 | @admincraft.route("/dataValues", methods=['GET'])
202 | @requires_auth
203 | def dataValues():
204 | selectedTheme = 'themes/%s/dataIcons.html' % config.THEME
205 | return render_template(selectedTheme)
206 |
207 | #/login will be for sessions. So far, only username is accepted with any value. Needs work here.
208 | @admincraft.route('/login', methods=['GET', 'POST'])
209 | def login():
210 | if request.method == 'POST':
211 | session['username'] = request.form['username']
212 | session['password'] = request.form['password']
213 | return redirect(url_for('admincraft.index'))
214 | selectedTheme = 'themes/%s/login.html' % config.THEME
215 | return render_template(selectedTheme)
216 |
217 | #Kill or Pop session when hitting /logout
218 | @admincraft.route('/logout')
219 | def logout():
220 | # remove the username from the session if its there
221 | session.pop('username', None)
222 | session.pop('password', None)
223 | return redirect(url_for('admincraft.index'))
224 |
225 | #/commandList is used to create a commandList.html view, which is then imported to Index. Used for "Command" on GUI.
226 | @admincraft.route('/commandList', methods=['GET', 'POST'])
227 | @requires_auth
228 | def commandList():
229 | selectedTheme = 'themes/%s/commandList.html' % config.THEME
230 | return render_template(selectedTheme)
231 |
232 | @admincraft.route('/tabs', methods=['GET', 'POST'])
233 | @requires_auth
234 | def tabs():
235 | #Read server.properties to display Server Properties on Server Config section. -2 first lines.
236 | propertiesFile = config.MINECRAFTDIR + config.SERVERPROPERTIES
237 | properties = open(propertiesFile, "r").readlines()[2:]
238 |
239 | #Read ops.txt to display Server Operators on Users section.
240 | opsFile = config.MINECRAFTDIR + config.SERVEROPS
241 | ops = open(opsFile, "r").readlines()
242 | ops = [i.rstrip() for i in ops]
243 |
244 | #Read white-list.txt to display Whitelisted on Users section.
245 | whiteListFile = config.MINECRAFTDIR + config.WHITELIST
246 | whiteListUsers = open(whiteListFile, "r").readlines()
247 | whiteListUsers = [i.rstrip() for i in whiteListUsers]
248 |
249 | #Read banned-players.txt to display Banned Players on Users section.
250 | bannedUsersFile = config.MINECRAFTDIR + config.BANNEDPLAYERS
251 | """
252 | bannedUsers = open(bannedUsersFile, "r").readlines()[2:]
253 | bannedUsers = [i.rstrip() for i in bannedUsers]
254 |
255 | #Read banned-ips.txt to display Banned IPs on Users section.
256 | bannedIPsFile = config.MINECRAFTDIR + config.BANNEDIPS
257 | bannedIPs = open(bannedIPsFile, "r").readlines()[2:]
258 | bannedIPs = [i.rstrip() for i in bannedIPs]
259 | """
260 |
261 | bannedUsers = csv.reader(open(bannedUsersFile, "r").readlines()[3:], delimiter='|', quoting=csv.QUOTE_ALL)
262 | #bannedUsers = [i.rstrip() for i in bannedUsers] #pre 1.3
263 | bannedUsersList = []
264 | for u in bannedUsers:
265 | bannedUsersList.append(u[0])
266 |
267 | #Read banned-ips.txt to display Banned IPs on Users section.
268 | bannedIPsFile = config.MINECRAFTDIR + config.BANNEDIPS
269 | bannedIPs = csv.reader(open(bannedIPsFile, "r").readlines()[3:], delimiter='|', quoting=csv.QUOTE_ALL)
270 | #bannedIPs = [i.rstrip() for i in bannedIPs]
271 | bannedIPsList = []
272 | for i in bannedIPs:
273 | bannedIPsList.append(i[0])
274 |
275 | #Ghetto method of shelling out the 'list' command to minecraft init script, which returns
276 | #the list of players in server.log. Grab last line of server.log, strip time/date
277 | #and determine whether players are connected or not. Rest of logic in Jinja2 tabs.html.
278 | subprocess.Popen(config.MINECRAFTDAEMON + ' command list', shell=True)
279 | sleep(1) #Unfortunately, the minecraft init commands lag a bit, so this is required to grab the last line correctly.
280 | activeUsersFile = config.MINECRAFTDIR + config.SERVERLOG
281 | activeUsers = open(activeUsersFile, "r").readlines()[-1:]
282 | activeUsers = [i.rstrip()[27:] for i in activeUsers]
283 | noUsers = "No players connected" #If activeUsers list is empty, Jinja2 will use this variable instead.
284 |
285 | backupDir = config.BACKUPDIR
286 |
287 | isRunning = Markup('Task Scheduler
Online
')
288 |
289 | #Connects to db to list scheduled jobs in a table
290 | dbpath = config.DATABASE
291 |
292 | conn = sqlite3.connect(dbpath)
293 | c = conn.cursor()
294 | c.execute('select * from tasks order by type')
295 | a = c.fetchall()
296 | conn.commit()
297 | c.close()
298 |
299 | selectedTheme = 'themes/%s/tabs.html' % config.THEME
300 | return render_template(selectedTheme, a=a, activeUsers=activeUsers, isRunning=isRunning, backupDir=backupDir, ops=ops, whiteListUsers=whiteListUsers, bannedUsersList=bannedUsersList, bannedIPsList=bannedIPsList, properties=properties)
301 |
302 | #/serverConfig is used for GET request via server property configurations.
303 | @admincraft.route('/serverConfig', methods=['GET'])
304 | @requires_auth
305 | def serverConfig():
306 | #Grab Vars from GET request
307 | generatorSettingsValue = request.args.get('generator-settings')
308 | allowNetherValue = request.args.get('allow-nether')
309 | levelNameValue = request.args.get('level-name')
310 | enableQueryValue = request.args.get('enable-query')
311 | allowFlightValue = request.args.get('allow-flight')
312 | serverPortValue = request.args.get('server-port')
313 | levelTypeValue = request.args.get('level-type')
314 | enableRconValue = request.args.get('enable-rcon')
315 | levelSeedValue = request.args.get('level-seed')
316 | forceGamemodeValue = request.args.get('force-gamemode')
317 | serverIPValue = request.args.get('server-ip')
318 | maxBuildHeightValue = request.args.get('max-build-height')
319 | spawnNPCsValue = request.args.get('spawn-npcs')
320 | whitelistValue = request.args.get('white-list')
321 | spawnAnimalsValue = request.args.get('spawn-animals')
322 | snooperEnabledValue = request.args.get('snooper-enabled')
323 | hardcoreValue = request.args.get('hardcore')
324 | texturePackValue = request.args.get('texture-pack')
325 | onlineModeValue = request.args.get('online-mode')
326 | pvpValue = request.args.get('pvp')
327 | difficultyValue = request.args.get('difficulty')
328 | gamemodeValue = request.args.get('gamemode')
329 | maxPlayersValue = request.args.get('max-players')
330 | spawnMonstersValue = request.args.get('spawn-monsters')
331 | generateStructuresValue = request.args.get('generate-structures')
332 | viewDistanceValue = request.args.get('view-distance')
333 | spawnProtectionValue = request.args.get('spawn-protection')
334 | motdValue = request.args.get('motd')
335 |
336 |
337 | GET_VARS = [
338 | (generatorSettingsValue, request.args.get('generator-settings') ),
339 | (allowNetherValue, request.args.get('allow-nether') ),
340 | (levelNameValue, request.args.get('level-name') ),
341 | (enableQueryValue, request.args.get('enable-query') ),
342 | (allowFlightValue, request.args.get('allow-flight') ),
343 | (serverPortValue, request.args.get('server-port') ),
344 | (levelTypeValue, request.args.get('level-type') ),
345 | (enableRconValue, request.args.get('enable-rcon') ),
346 | (levelSeedValue, request.args.get('level-seed') ),
347 | (forceGamemodeValue, request.args.get('force-gamemode') ),
348 | (serverIPValue, request.args.get('server-ip') ),
349 | (maxBuildHeightValue, request.args.get('build-height') ),
350 | (spawnNPCsValue, request.args.get('spawn-npcs') ),
351 | (whitelistValue, request.args.get('white-list') ),
352 | (spawnAnimalsValue, request.args.get('spawn-animals') ),
353 | (snooperEnabledValue, request.args.get('snooper-enabled') ),
354 | (hardcoreValue, request.args.get('request.args.get-hardcore')),
355 | (texturePackValue, request.args.get('texture-pack') ),
356 | (onlineModeValue, request.args.get('online-mode') ),
357 | (pvpValue, request.args.get('request.args.get-pvp')),
358 | (difficultyValue, request.args.get('request.args.get-difficulty')),
359 | (gamemodeValue, request.args.get('request.args.get-gamemode')),
360 | (maxPlayersValue, request.args.get('max-players') ),
361 | (spawnMonstersValue, request.args.get('spawn-monsters') ),
362 | (generateStructuresValue,request.args.get('generate-structures') ),
363 | (viewDistanceValue, request.args.get('view-distance') ),
364 | (spawnProtectionValue, request.args.get('spawn-protection') ),
365 | (motdValue, request.args.get('request.args.get-motd'))
366 | ]
367 |
368 | #Set server.properties
369 | p = config.MINECRAFTDIR + config.SERVERPROPERTIES
370 |
371 | #Open properties as f with read and write permissions.
372 | f = open(p, "r+")
373 | pText = f.readlines()
374 |
375 | #Each line is read. If line-item contains X text, then use value. Set as pOutput.
376 | for pItem in pText:
377 | if "generator-settings" in pItem:
378 | pOutput = [w.replace(pItem, "generator-settings" + '=' + generatorSettingsValue + '\n') for w in pText]
379 |
380 | for pItem in pOutput:
381 | if "allow-nether" in pItem:
382 | pOutput = [w.replace(pItem, "allow-nether" + '=' + allowNetherValue + '\n') for w in pOutput]
383 |
384 | for pItem in pOutput:
385 | if "level-name" in pItem:
386 | pOutput = [w.replace(pItem, "level-name" + '=' + levelNameValue + '\n') for w in pOutput]
387 |
388 | for pItem in pOutput:
389 | if "enable-query" in pItem:
390 | pOutput = [w.replace(pItem, "enable-query" + '=' + enableQueryValue + '\n') for w in pOutput]
391 |
392 | for pItem in pOutput:
393 | if "allow-flight" in pItem:
394 | pOutput = [w.replace(pItem, "allow-flight" + '=' + allowFlightValue + '\n') for w in pOutput]
395 |
396 | for pItem in pOutput:
397 | if "server-port" in pItem:
398 | pOutput = [w.replace(pItem, "server-port" + '=' + serverPortValue + '\n') for w in pOutput]
399 |
400 | for pItem in pOutput:
401 | if "level-type" in pItem:
402 | pOutput = [w.replace(pItem, "level-type" + '=' + levelTypeValue + '\n') for w in pOutput]
403 |
404 | for pItem in pOutput:
405 | if "enable-rcon" in pItem:
406 | pOutput = [w.replace(pItem, "enable-rcon" + '=' + enableRconValue + '\n') for w in pOutput]
407 |
408 | for pItem in pOutput:
409 | if "level-seed" in pItem:
410 | pOutput = [w.replace(pItem, "level-seed" + '=' + levelSeedValue + '\n') for w in pOutput]
411 |
412 | for pItem in pOutput:
413 | if "force-gamemode" in pItem:
414 | pOutput = [w.replace(pItem, "force-gamemode" + '=' + forceGamemodeValue + '\n') for w in pOutput]
415 |
416 | for pItem in pOutput:
417 | if "server-ip" in pItem:
418 | pOutput = [w.replace(pItem, "server-ip" + '=' + serverIPValue + '\n') for w in pOutput]
419 |
420 | for pItem in pOutput:
421 | if "max-build-height" in pItem:
422 | pOutput = [w.replace(pItem, "max-build-height" + '=' + maxBuildHeightValue + '\n') for w in pOutput]
423 |
424 | for pItem in pOutput:
425 | if "spawn-npcs" in pItem:
426 | pOutput = [w.replace(pItem, "spawn-npcs" + '=' + spawnNPCsValue + '\n') for w in pOutput]
427 |
428 | for pItem in pOutput:
429 | if "white-list" in pItem:
430 | pOutput = [w.replace(pItem, "white-list" + '=' + whitelistValue + '\n') for w in pOutput]
431 |
432 | for pItem in pOutput:
433 | if "spawn-animals" in pItem:
434 | pOutput = [w.replace(pItem, "spawn-animals" + '=' + spawnAnimalsValue + '\n') for w in pOutput]
435 |
436 | for pItem in pOutput:
437 | if "snooper-enabled" in pItem:
438 | pOutput = [w.replace(pItem, "snooper-enabled" + '=' + snooperEnabledValue + '\n') for w in pOutput]
439 |
440 | for pItem in pOutput:
441 | if "texture-pack" in pItem:
442 | pOutput = [w.replace(pItem, "texture-pack" + '=' + texturePackValue + '\n') for w in pOutput]
443 |
444 | for pItem in pOutput:
445 | if "online-mode" in pItem:
446 | pOutput = [w.replace(pItem, "online-mode" + '=' + onlineModeValue + '\n') for w in pOutput]
447 |
448 | for pItem in pOutput:
449 | if "pvp" in pItem:
450 | pOutput = [w.replace(pItem, "pvp" + '=' + pvpValue + '\n') for w in pOutput]
451 |
452 | for pItem in pOutput:
453 | if "difficulty" in pItem:
454 | pOutput = [w.replace(pItem, "difficulty" + '=' + difficultyValue + '\n') for w in pOutput]
455 |
456 | for pItem in pOutput:
457 | if "gamemode" in pItem:
458 | pOutput = [w.replace(pItem, "gamemode" + '=' + gamemodeValue + '\n') for w in pOutput]
459 |
460 | for pItem in pOutput:
461 | if "max-players" in pItem:
462 | pOutput = [w.replace(pItem, "max-players" + '=' + maxPlayersValue + '\n') for w in pOutput]
463 |
464 | for pItem in pOutput:
465 | if "spawn-monsters" in pItem:
466 | pOutput = [w.replace(pItem, "spawn-monsters" + '=' + spawnMonstersValue + '\n') for w in pOutput]
467 |
468 | for pItem in pOutput:
469 | if "generate-structures" in pItem:
470 | pOutput = [w.replace(pItem, "generate-structures" + '=' + generateStructuresValue + '\n') for w in pOutput]
471 |
472 | for pItem in pOutput:
473 | if "view-distance" in pItem:
474 | pOutput = [w.replace(pItem, "view-distance" + '=' + viewDistanceValue + '\n') for w in pOutput]
475 |
476 | for pItem in pOutput:
477 | if "motd" in pItem:
478 | pOutput = [w.replace(pItem, "motd" + '=' + motdValue + '\n') for w in pOutput]
479 |
480 | #Close file for reading. Re-open as write and write out pOutput to file.
481 | f.writelines(pOutput)
482 | f.close()
483 | return redirect(url_for('admincraft.index'))
484 | #return render_template('serverConfig.html', pOutput=pOutput)
485 |
486 | #/usersConfig - Adds/Removes users from User Config
487 | @admincraft.route('/addUser', methods=['GET', 'POST'])
488 | @requires_auth
489 | def addUser():
490 | addType = request.args.get('type')
491 | addValue = request.args.get('user')
492 |
493 | if addType == "operators":
494 | f = config.MINECRAFTDIR + config.SERVEROPS
495 | elif addType == "whitelist":
496 | f = config.MINECRAFTDIR + config.WHITELIST
497 | elif addType == "banned-players":
498 | f = config.MINECRAFTDIR + config.BANNEDPLAYERS
499 | elif addType == "banned-ips":
500 | f = config.MINECRAFTDIR + config.BANNEDIPS
501 | else:
502 | print "Error reading Add Type"
503 |
504 | #Open f as o and append value.
505 | with open(f, "a") as o:
506 | o.write(addValue + "\n")
507 |
508 | o.close()
509 |
510 | return "User Added"
511 |
512 | @admincraft.route('/removeUser', methods=['GET', 'POST'])
513 | @requires_auth
514 | def removeUser():
515 | #Grab vars from GET request
516 | removeType = request.args.get('type')
517 | removeValue = request.args.get('user')
518 |
519 | if removeType == "operators":
520 | f = config.MINECRAFTDIR + config.SERVEROPS
521 | elif removeType == "whitelist":
522 | f = config.MINECRAFTDIR + config.WHITELIST
523 | elif removeType == "banned-players":
524 | f = config.MINECRAFTDIR + config.BANNEDPLAYERS
525 | elif removeType == "banned-ips":
526 | f = config.MINECRAFTDIR + config.BANNEDIPS
527 | else:
528 | print "Error reading Remove Type"
529 |
530 | #Open f and read out lines
531 | o = open(f, "r+").readlines()
532 |
533 | #Create a list as ops, minus the removeValue
534 | ops = []
535 | ops = [names for names in o if names != removeValue + "\n"]
536 |
537 | #Open ops.txt for writing and write out new lines
538 | o.writelines(ops)
539 | o.close()
540 |
541 | return "User Removed"
542 |
543 | @admincraft.route('/task', methods=['GET'])
544 | @requires_auth
545 | def taskService():
546 | command = request.args.get("command")
547 |
548 | if command == "stop":
549 | stopTaskDaemon()
550 | return 'Shutting down task daemon...'
551 | elif command == "start":
552 | startTaskDaemon()
553 | return 'Starting task daemon...'
554 | elif command == "restart":
555 | stopTaskDaemon()
556 | startTaskDaemon()
557 | return 'Restarting task daemon...'
558 | elif command == "status":
559 | status = checkStatus()
560 | return status
561 |
562 | @admincraft.route('/addTask', methods=['POST', 'GET'])
563 | @requires_auth
564 | def addTask():
565 | dbpath = config.DATABASE
566 |
567 | task = request.args.get("type")
568 | dom = request.args.get("dom")
569 | dow = request.args.get("dow")
570 | hour = request.args.get("hour")
571 | minute = request.args.get("minute")
572 |
573 | v = [task, dom, dow, hour, minute]
574 |
575 | conn = sqlite3.connect(dbpath)
576 | c = conn.cursor()
577 |
578 | if not os.path.exists(dbpath):
579 | c.execute('''create table tasks (type text, month text, day text, hour text, minute text)''')
580 |
581 | else:
582 | c.execute("INSERT into tasks VALUES (?,?,?,?,?)", v)
583 | c.execute('select * from tasks order by type')
584 |
585 | for row in c:
586 | print row
587 |
588 |
589 | conn.commit()
590 | c.close()
591 | return 'Task saved.'
592 |
593 | #Turn on later
594 | #@admincraft.errorhandler(500)
595 | #def not_found(error):
596 | # return render_template('themes/%s/500.html' % config.THEME), 500
597 |
598 | #@admincraft.errorhandler(404)
599 | #def not_found(error):
600 | # return render_template('themes/%s/404.html' % config.THEME), 404
601 |
602 |
603 |
--------------------------------------------------------------------------------
/static/themes/default/jquery-ui/etc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | jQuery UI Example Page
6 |
7 |
8 |
9 |
63 |
73 |
74 |
75 |
Welcome to jQuery UI!
76 |
This page demonstrates the widgets you downloaded using the theme you selected in the download builder. We've included and linked to minified versions of jQuery, your personalized copy of jQuery UI (js/jquery-ui-1.8.16.custom.min.js), and css/ui-lightness/jquery-ui-1.8.16.custom.css which imports the entire jQuery UI CSS Framework. You can choose to link a subset of the CSS Framework depending on your needs.
77 |
You've downloaded components and a theme that are compatible with jQuery 1.3+. Please make sure you are using jQuery 1.3+ in your production environment.
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
107 |
Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum.
108 |
Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.
Overlay and Shadow Classes (not currently used in UI widgets)
117 |
118 |
Lorem ipsum dolor sit amet, Nulla nec tortor. Donec id elit quis purus consectetur consequat.
Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci.
Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat.
Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.
Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.
Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi.
119 |
120 |
121 |
122 |
123 |
124 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.