├── .bowerrc ├── .gitignore ├── DockerBackend.py ├── README.md ├── bower.json ├── build-all.sh ├── config.cfg.template ├── dhbox.py ├── dist ├── static │ ├── css │ │ └── dhbox.css │ ├── favicon.ico │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── images │ │ ├── britishlibrary-logo.gif │ │ ├── cuny-logo.jpg │ │ ├── dhbox_shell.png │ │ ├── dhsi-logo.jpg │ │ ├── hilt-logo.png │ │ ├── ipython-logo.png │ │ ├── logo.png │ │ ├── nypl-logo.jpg │ │ ├── omeka-logo.gif │ │ └── rstudio-logo.png │ └── js │ │ └── dhbox.js └── templates │ ├── about.html │ ├── admin.html │ ├── contact.html │ ├── dhbox.html │ ├── get_started.html │ ├── index.html │ ├── layout.html │ ├── news.html │ ├── our_team.html │ ├── port.html │ ├── security │ └── login_user.html │ ├── signup.html │ └── test.html ├── gulpfile.js ├── install_dhbox.sh ├── lamp-seed ├── Dockerfile ├── LICENSE ├── README.md ├── apache_default ├── create_mysql_admin_user.sh ├── my.cnf ├── run.sh ├── start-apache2.sh ├── start-mysqld.sh ├── supervisord-apache2.conf ├── supervisord-mysqld.conf └── tutum.yml ├── license.md ├── manage.py ├── package.json ├── requirements.txt ├── seed ├── Dockerfile ├── conda.sh ├── index.html ├── omeka │ ├── config.ini │ ├── db.ini │ ├── htaccess │ ├── omeka.conf │ ├── playbook.yml │ ├── tasks │ │ ├── apache.yml │ │ ├── config.yml │ │ ├── db.yml │ │ ├── install.yml │ │ └── omeka.yml │ └── templates │ │ ├── config.ini │ │ ├── db.ini.j2 │ │ └── omeka.conf.j2 └── runit_scripts │ ├── apache2.sh │ ├── brackets.sh │ ├── explorer.sh │ ├── mysql.sh │ ├── notebook.sh │ ├── rserver.sh │ ├── smtpd.sh │ ├── startup.sh │ └── wetty.sh ├── src ├── static │ ├── css │ │ └── main.less │ ├── favicon.ico │ ├── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── images │ │ ├── britishlibrary-logo.gif │ │ ├── cuny-logo.jpg │ │ ├── dhbox_shell.png │ │ ├── dhsi-logo.jpg │ │ ├── hilt-logo.png │ │ ├── ipython-logo.png │ │ ├── logo.png │ │ ├── nypl-logo.jpg │ │ ├── omeka-logo.gif │ │ └── rstudio-logo.png │ └── js │ │ └── main.js └── templates │ ├── .gitignore │ ├── about.html │ ├── admin.html │ ├── contact.html │ ├── dhbox.html │ ├── get_started.html │ ├── index.html │ ├── layout.html │ ├── news.html │ ├── our_team.html │ ├── port.html │ ├── security │ └── login_user.html │ ├── signup.html │ └── test.html ├── static └── css │ ├── bootstrap-dialog.min.css │ ├── custom.css │ ├── modals.css │ └── my_dhbox.css ├── wp-seed ├── Dockerfile ├── LICENSE ├── README.md ├── create_db.sh ├── create_mysql_admin_user.sh ├── tutum.yml └── wp-config.php └── wsgi.py /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/static/bower_components" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.db 3 | hosts 4 | *.cfg 5 | *.python-version 6 | *.py[cod] 7 | 8 | # Emacs 9 | *# 10 | *~ 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Packages 16 | *.egg 17 | *.egg-info 18 | build 19 | eggs 20 | parts 21 | bin 22 | var 23 | sdist 24 | develop-eggs 25 | .installed.cfg 26 | lib 27 | lib64 28 | 29 | # Installer logs 30 | pip-log.txt 31 | 32 | # Unit test / coverage reports 33 | .coverage 34 | .tox 35 | nosetests.xml 36 | 37 | # Translations 38 | *.mo 39 | 40 | # Mr Developer 41 | .mr.developer.cfg 42 | .project 43 | .pydevproject 44 | 45 | # Virtualenv 46 | .Python 47 | bin 48 | lib 49 | include 50 | 51 | # Mac OS X custom attribute files 52 | .DS_Store 53 | 54 | 55 | .vagrant/ 56 | instance/ 57 | 58 | # pycharm settings 59 | .idea 60 | 61 | # js packages 62 | src/static/bower_components/ 63 | node_modules/ 64 | 65 | *.log 66 | -------------------------------------------------------------------------------- /DockerBackend.py: -------------------------------------------------------------------------------- 1 | import docker 2 | from docker import Client 3 | from docker.utils import kwargs_from_env 4 | import json 5 | from urllib2 import urlopen 6 | import os, time, subprocess 7 | from threading import Timer 8 | import logging 9 | import ipgetter 10 | import datetime as dt 11 | import dhbox 12 | 13 | 14 | dhbox_repo = 'thedhbox' 15 | gotten_ip = ipgetter.myip() 16 | 17 | # logging.basicConfig(filename='dhbox.log',level=logging.ERROR) 18 | 19 | 20 | def attach_to_docker_client(): 21 | if os.getenv('DOCKER_HOST') == 'tcp://192.168.59.103:2376': 22 | c = Client(**kwargs_from_env(assert_hostname=False)) 23 | else: 24 | c = Client() 25 | return c 26 | 27 | 28 | def get_hostname(): 29 | """Determine the IP address of the host server""" 30 | if os.getenv('DOCKER_HOST') == 'tcp://192.168.59.103:2376': 31 | hostname = 'dockerhost' 32 | else: 33 | if dhbox.app.config['LOCALHOST']: 34 | hostname = 'localhost' 35 | else: 36 | hostname = gotten_ip or dhbox.app.config['DEFAULT_HOSTNAME'] 37 | return hostname 38 | 39 | 40 | def download_dhbox(username='test'): 41 | """Downloads a DH Box seed, renaming the old one if it exists""" 42 | print "Downloading Seed" 43 | images = c.images() 44 | for image in images: 45 | if image["RepoTags"] == [dhbox_repo+"/seed:latest"]: 46 | image_id = image["Id"] 47 | c.tag(image=image_id, repository=dhbox_repo+'/seed', tag='older', force=True) 48 | for line in c.pull(dhbox_repo+'/seed:latest', stream=True): 49 | print(json.dumps(json.loads(line), indent=4)) 50 | # for line in c.pull(dhbox_repo+'/twordpress:latest', stream=True): 51 | # print(json.dumps(json.loads(line), indent=4)) 52 | 53 | 54 | def build_dhbox(username='test'): 55 | """Builds a new Dh Box seed, renaming the old one if it exists""" 56 | print "Building Seed" 57 | images = c.images() 58 | for image in images: 59 | if image["RepoTags"] == [dhbox_repo+"/seed:latest"]: 60 | image_id = image["Id"] 61 | c.tag(image=image_id, repository=dhbox_repo+'/seed', tag='older', force=True) 62 | os.chdir('seed/') 63 | for line in c.build(path='.', rm=True, tag=dhbox_repo+'/seed:latest'): 64 | print line 65 | if "errorDetail" in line: 66 | # There was an error, so kill the container and the image 67 | pass 68 | os.chdir('../') 69 | 70 | 71 | def all_containers(): 72 | info = c.containers(all=True) 73 | return info 74 | 75 | 76 | def get_container_info(which_container): 77 | info = c.inspect_container(which_container) 78 | return info 79 | 80 | 81 | def get_container_port(container_name, app_port): 82 | container = get_container_info(container_name) 83 | public_port = container['NetworkSettings']['Ports'][app_port + '/tcp'][0]['HostPort'] 84 | return public_port 85 | 86 | 87 | def get_all_exposed_ports(container_name): 88 | container = get_container_info(container_name) 89 | public_ports = container['NetworkSettings']['Ports'] 90 | public_ports_cleaned = {} 91 | for inside_port, outside_port in public_ports.iteritems(): 92 | inside_port = inside_port[:-4] 93 | outside_port = outside_port[0]['HostPort'] 94 | public_ports_cleaned[inside_port] = outside_port 95 | return public_ports_cleaned 96 | 97 | 98 | def setup_new_dhbox(username, password, email, demo=False): 99 | """Create a new DH Box container, customize it.""" 100 | environment = {"PASS": password, "EMAIL": email, "THEUSER": username, "DEMO": demo} 101 | if demo: 102 | environment = {"PASS": 'demonstration', "EMAIL": email, "THEUSER": 'demonstration', "DEMO": demo} 103 | try: 104 | # ports = [(lambda x: app['port'] for app in dhbox.all_apps if app['port'] != None)] 105 | # print ports 106 | print "Creating Containers" 107 | # wp_container = c.create_container(image=dhbox_repo+"/twordpress:latest", 108 | # name=username+'_wp', 109 | # ports=[80],) 110 | container = c.create_container(image=dhbox_repo+'/seed:latest', name=username, 111 | ports=[8080, 8081, 8787, 4444, 4200, 3000, 8888], 112 | tty=True, stdin_open=True, 113 | environment=environment) 114 | except docker.errors.APIError, e: 115 | print e 116 | raise e 117 | else: 118 | print "Starting Containers" 119 | restart_policy = {"Name": "always"} 120 | # c.start(wp_container, 121 | # publish_all_ports=True, restart_policy=restart_policy) 122 | # c.start(container, publish_all_ports=True, volumes_from=username+'_wp', restart_policy=restart_policy) 123 | # configure_dhbox(username, password, email, demo=demo) 124 | c.start(container, publish_all_ports=True, restart_policy=restart_policy) 125 | configure_dhbox(username, password, email, demo=demo) 126 | info = c.inspect_container(container) 127 | return info 128 | 129 | 130 | def execute(container, args): 131 | """Execute a list of arbitrary Bash commands inside a container""" 132 | for arg in args: 133 | # print arg 134 | exec_instance = c.exec_create(container=container, cmd=arg) 135 | return c.exec_start(exec_instance) 136 | 137 | 138 | def configure_dhbox(user, the_pass, email, demo=False): 139 | """Use Docker exec to SSH into a new container, customizing it for the user. 140 | Adds the user to Omeka. """ 141 | container = user 142 | if demo: 143 | user = 'demonstration' 144 | omeka_string = 'wget -O /tmp/install.html --post-data "username={0}&password={1}&password_confirm={1}&super_email={2}&administrator_email={2}&site_title=DHBox&description=DHBox©right=2014&author=DHBOX&tag_delimiter=,&fullsize_constraint=800&thumbnail_constraint=200&square_thumbnail_constraint=200&per_page_admin=10&per_page_public=10&show_empty_elements=0&path_to_convert=/usr/bin&install_submit=Install" localhost:8080/install/install.php'.format( 145 | user, the_pass, email) 146 | time.sleep(5) 147 | execute(container, [omeka_string]) 148 | 149 | 150 | def demo_dhbox(username): 151 | """Make a demonstration DH Box with a random name. Expires in an hour.""" 152 | password = 'demonstration' 153 | email = username + '@demo.com' 154 | setup_new_dhbox(username, password, email, demo=True) 155 | 156 | 157 | def add_user(container, username, password): 158 | """Add a user to a running DH Box""" 159 | execute(container, ["useradd " + username]) 160 | execute(container, ["echo " + username + ":" + password + " | chpasswd"]) 161 | 162 | 163 | def kill_and_remove_user(name, user=True): 164 | """Kill a running DH Box container and remove the user if there is one""" 165 | try: 166 | print "Killing container." 167 | c.kill(name) 168 | # c.kill(name+'_wp') 169 | c.remove_container(name) 170 | # c.remove_container(name+'_wp') 171 | if user: 172 | dhbox.delete_user(name) 173 | except (docker.errors.NotFound, docker.errors.APIError) as e: 174 | print "Could not kill container ", name 175 | if user: 176 | dhbox.delete_user(name) 177 | return e 178 | 179 | 180 | def delete_untagged(): 181 | """Find the untagged images and remove them""" 182 | images = c.images() 183 | found = False 184 | for image in images: 185 | if image["RepoTags"] == [":"]: 186 | found = True 187 | image_id = image["Id"] 188 | print "Deleting untagged image\nhash=", image_id 189 | try: 190 | c.remove_image(image["Id"]) 191 | except docker.errors.APIError as error: 192 | print "Failed to delete image\nhash={}\terror={}", image_id, error 193 | 194 | if not found: 195 | print "Didn't find any untagged images to delete!" 196 | 197 | 198 | def how_long_up(container): 199 | """Find out how long a container has been running, in seconds""" 200 | try: 201 | detail = c.inspect_container(container) 202 | time_started = dt.datetime.strptime(detail['Created'][:-4], '%Y-%m-%dT%H:%M:%S.%f') 203 | time_up = dt.datetime.utcnow() - time_started 204 | return time_up.total_seconds() 205 | except docker.errors.NotFound, e: 206 | return e 207 | 208 | 209 | def check_if_over_time(user): 210 | try: 211 | duration = user.dhbox_duration - how_long_up(user.name) 212 | return duration 213 | except docker.errors.NotFound, e: 214 | return e 215 | 216 | 217 | def check_and_kill(user): 218 | """Checks a container's uptime and kills it and the user if time is up""" 219 | try: 220 | get_container_info(user.name) 221 | time_left = user.dhbox_duration - how_long_up(user.name) 222 | # print user.name, " time left: ", time_left, " seconds" 223 | if time_left <= 0: 224 | kill_and_remove_user(user.name) 225 | except docker.errors.NotFound: 226 | dhbox.delete_user(user.name) 227 | 228 | 229 | def replace_admin_dhbox_image(): 230 | """Updates admin's DH Box to the new seed image.""" 231 | kill_and_remove_user('admin', user=False) 232 | dhbox.create_user_and_role() 233 | # setup_new_dhbox('admin', dhbox.app.config['ADMIN_PASS'], dhbox.app.config['ADMIN_EMAIL'], demo=False) 234 | 235 | 236 | def display_time(seconds, granularity=2): 237 | intervals = ( 238 | ('weeks', 604800), # 60 * 60 * 24 * 7 239 | ('days', 86400), # 60 * 60 * 24 240 | ('hours', 3600), # 60 * 60 241 | ('minutes', 60), 242 | ('seconds', 1), 243 | ) 244 | result = [] 245 | for name, count in intervals: 246 | value = seconds // count 247 | if value: 248 | seconds -= value * count 249 | if value == 1: 250 | name = name.rstrip('s') 251 | result.append("{} {}".format(value, name)) 252 | return ', '.join(result[:granularity]) 253 | 254 | 255 | c = attach_to_docker_client() 256 | 257 | 258 | if __name__ == '__main__': 259 | c = attach_to_docker_client() 260 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DH Box 2 | ===== 3 | 4 | A toolbox for Digital Humanities. 5 | 6 | ### DH BOX Local Install Process 7 | Currently DH Box requires Ubuntu >= 14.04 and Python 2.7x 8 | ### One line install: 9 | ``` 10 | wget -qO- https://raw.githubusercontent.com/DH-Box/dhbox/master/install_dhbox.sh | sudo sh 11 | ``` 12 | 1. Navigate to `dhbox/` 13 | 2. Rename `config.cfg.template` to `config.cfg` and edit settings as desired 14 | 3. Run `sudo python manage.py build_database` 15 | 4. Run `sudo python wsgi.py` 16 | 5. Navigate to site on `http://localhost:80` 17 | 18 | #### Or for a manual install: 19 | 20 | 1. [Install Docker](https://www.docker.com/) 21 | 2. Install `pip`, Python package manager 22 | 3. Clone git repo (`git clone https://github.com/DH-Box/dhbox.git`) 23 | 4. Navigate to `dhbox/` 24 | 5. Run `pip install -r requirements.txt` (preferably in a virtualenv) 25 | 6. Rename `config.cfg.template` to `config.cfg` and edit settings as desired 26 | 7. Run `sudo manage start` to download the DH Box seed, or navigate to `dhbox/seed` and run `docker build -t thedhbox/seed:latest .` if you want to build it yourself (takes 15 minutes or more). 27 | 8. Run `sudo manage build_database` 28 | 9. Run `sudo python wsgi.py` 29 | 10. Navigate to site on `http://localhost:80` 30 | 31 | ### If you are developing for DH Box, there are a few more steps: 32 | 33 | 11. Install Node and Node Package Manager: `apt-get install nodejs npm` 34 | 12. Install Gulp and Bower: `npm install gulp bower` 35 | 13. Changes to the site go into the `/src` directory. Propagate changes with `gulp build` 36 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dhbox", 3 | "version": "0.0.0", 4 | "homepage": "http://dhbox.org", 5 | "authors": [ 6 | "DHBox Team" 7 | ], 8 | "description": "A push-button Digital Humanities laboratory.", 9 | "directory": "src/static/bower_components", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests" 16 | ], 17 | "dependencies": { 18 | "bootstrap": "~3.3.6", 19 | "less": "~2.5.1", 20 | "jquery-validate": "~1.13.1", 21 | "bootstrap-dialog": "~1.34.9", 22 | "fontawesome": "~4.3.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /build-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd seed/ 3 | sudo docker build -t thedhbox/seed:latest . 4 | cd ../lamp-seed/ 5 | sudo docker build -t thedhbox/tlamp . 6 | cd ../wp-seed/ 7 | sudo docker build -t thedhbox/twordpress . 8 | -------------------------------------------------------------------------------- /config.cfg.template: -------------------------------------------------------------------------------- 1 | SQLALCHEMY_DATABASE_URI = 'sqlite:///dhbox-docker.db' 2 | SECURITY_RECOVERABLE = True 3 | SECURITY_USER_IDENTITY_ATTRIBUTES = 'name' 4 | SECRET_KEY = 'something secret' 5 | TESTING = False 6 | DEMO_ENABLED = True 7 | LOCALHOST = False 8 | DEFAULT_HOSTNAME = 'localhost' 9 | ADMIN_PASS = 'asecret' 10 | ADMIN_EMAIL = 'fake@fake.com' 11 | INSTITUTION = 'CUNY Graduate Center' 12 | -------------------------------------------------------------------------------- /dhbox.py: -------------------------------------------------------------------------------- 1 | import os, os.path, random, string, time, urllib2 2 | from flask import Flask, flash, request, redirect, url_for, render_template, \ 3 | make_response, abort 4 | import ast 5 | from flask_sqlalchemy import SQLAlchemy 6 | from flask_security import Security, SQLAlchemyUserDatastore, login_user, logout_user, \ 7 | UserMixin, RoleMixin, login_required, roles_required, current_user, LoginForm 8 | from flaskext.markdown import Markdown 9 | from wtforms.validators import DataRequired 10 | from wtforms import TextField, Form 11 | from werkzeug import generate_password_hash, check_password_hash 12 | from werkzeug.contrib.fixers import ProxyFix 13 | import schedule 14 | from threading import Thread 15 | import DockerBackend 16 | 17 | # create application 18 | app = Flask('dhbox') 19 | app.wsgi_app = ProxyFix(app.wsgi_app) 20 | Markdown(app) 21 | # install_secret_key(app) 22 | app.config.from_pyfile('config.cfg') 23 | # app.template_folder = 'src/templates' if app.config['TESTING'] else 'dist/templates' 24 | # app.static_folder = 'src/static' if app.config['TESTING'] else 'dist/static' 25 | app.template_folder = 'dist/templates' 26 | app.static_folder = 'dist/static' 27 | # Create database connection object 28 | db = SQLAlchemy(app) 29 | 30 | all_apps = [ 31 | {'name': 'mallet', 'wiki-page': 'MALLET', 'display-name': 'MALLET'}, 32 | {'name': 'ntlk', 'wiki-page': 'NLTK', 'display-name': 'NLTK'}, 33 | {'name': 'filemanager', 'port': '8081', 'wiki-page': 'manager', 'display-name': 'File Manager'}, 34 | {'name': 'bash', 'port': '4200', 'wiki-page': 'Bash-shell', 'display-name': 'Command Line', 'height': 500}, 35 | {'name': 'rstudio', 'port': '8787', 'wiki-page': 'R-Studio', 'display-name': 'R Studio'}, 36 | {'name': 'brackets', 'port': '4444', 'wiki-page': 'Brackets', 'display-name': 'Brackets'}, 37 | {'name': 'apache', 'port': '80', 'hide': True}, 38 | {'name': 'jupyter', 'port': '8888', 'wiki-page': 'ipython', 'display-name': 'Jupyter Notebooks'}, 39 | # {'name': 'wordpress', 'port': '80', 'wiki-page': 'wordpress', 'display-name': 'WordPress'} 40 | # {'name': 'website', 'port': '4000', 'wiki-page': 'webpage', 'display-name': 'Your Site'} 41 | ] 42 | 43 | 44 | def get_app(key): 45 | for app in all_apps: 46 | if app['name'] == key: 47 | return app 48 | 49 | """ 50 | MODELS 51 | """ 52 | roles_users = db.Table('roles_users', 53 | db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), 54 | db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))) 55 | 56 | 57 | class Role(db.Model, RoleMixin): 58 | id = db.Column(db.Integer(), primary_key=True) 59 | name = db.Column(db.String(80), unique=True) 60 | description = db.Column(db.String(255)) 61 | 62 | 63 | class User(db.Model, UserMixin): 64 | id = db.Column(db.Integer, primary_key=True) 65 | email = db.Column(db.String(255), unique=True) 66 | name = db.Column(db.String(255), unique=True) 67 | pwdhash = db.Column(db.String(160)) 68 | active = db.Column(db.Boolean()) 69 | dhbox_duration = db.Column(db.Integer) 70 | confirmed_at = db.Column(db.DateTime()) 71 | roles = db.relationship('Role', secondary=roles_users, 72 | backref=db.backref('users', lazy='dynamic')) 73 | 74 | def __init__(self, name, active, roles, email, password, dhbox_duration): 75 | self.name = name 76 | self.email = email.lower() 77 | self.active = active 78 | self.roles = roles 79 | self.dhbox_duration = dhbox_duration 80 | self.set_password(password) 81 | 82 | def set_password(self, password): 83 | self.pwdhash = generate_password_hash(password) 84 | 85 | def check_password(self, password): 86 | return check_password_hash(self.pwdhash, password) 87 | 88 | 89 | class ExtendedLoginForm(LoginForm): 90 | name = TextField('Name', [DataRequired()]) 91 | 92 | def validate(self): 93 | rv = Form.validate(self) 94 | if not rv: 95 | return False 96 | 97 | user = User.query.filter_by( 98 | name=self.name.data).first() 99 | if user is None: 100 | self.name.errors.append('Unknown username') 101 | return False 102 | 103 | if not user.check_password(self.password.data): 104 | self.password.errors.append('Invalid password') 105 | return False 106 | 107 | self.user = user 108 | return True 109 | 110 | # Setup Flask-Security 111 | user_datastore = SQLAlchemyUserDatastore(db, User, Role) 112 | security = Security(app, user_datastore, login_form=ExtendedLoginForm) 113 | 114 | 115 | # Create an admin user to test with 116 | def create_user_and_role(): 117 | first_user = User.query.filter(User.name == 'admin').first() 118 | if not first_user: 119 | user_email = app.config['ADMIN_EMAIL'] 120 | username = 'admin' 121 | user_pass = app.config['ADMIN_PASS'] 122 | the_user = user_datastore.create_user(email=user_email, name=username, password=user_pass, dhbox_duration=1000000000) 123 | check_admin_role = Role.query.filter(Role.name == 'admin').first() 124 | if not check_admin_role: 125 | the_role = user_datastore.create_role(name='admin', description='The administrator') 126 | user_datastore.add_role_to_user(the_user, the_role) 127 | else: 128 | user_datastore.add_role_to_user(the_user, check_admin_role) 129 | db.session.commit() 130 | try: 131 | DockerBackend.get_container_info(username) 132 | print 'already have a container' 133 | except Exception: 134 | DockerBackend.setup_new_dhbox(username, user_pass, user_email) 135 | 136 | 137 | def delete_user(user): 138 | try: 139 | user = User.query.filter(User.name == user).first() 140 | db.session.delete(user) 141 | db.session.commit() 142 | except Exception, e: 143 | print e 144 | 145 | 146 | """ 147 | URLS/VIEWS 148 | """ 149 | 150 | @app.route("/") 151 | def index(): 152 | return render_template('index.html', institution=app.config['INSTITUTION'], demo=app.config['DEMO_ENABLED']) 153 | 154 | 155 | @app.route("/signup") 156 | def signup(): 157 | return render_template('signup.html') 158 | 159 | 160 | @app.route('/about') 161 | def about(): 162 | return render_template('about.html') 163 | 164 | 165 | @app.route('/contact') 166 | def contact(): 167 | return render_template('contact.html') 168 | 169 | 170 | @app.route('/our_team') 171 | def our_team(): 172 | return render_template('our_team.html') 173 | 174 | 175 | @app.route('/news') 176 | def news(): 177 | news_folder = 'src/templates/news/' 178 | news_list = [] 179 | for file in os.listdir(news_folder): 180 | with open(news_folder + file) as f: 181 | content = f.read() 182 | news_list.append(content) 183 | return render_template('news.html', news_list=news_list) 184 | 185 | 186 | @app.route('/port_4000') 187 | def port_4000(): 188 | return render_template('port.html') 189 | 190 | 191 | @app.route('/get_started') 192 | def get_started(): 193 | return render_template('get_started.html') 194 | 195 | 196 | @app.route("/login", methods=["GET", "POST"]) 197 | def login(): 198 | # form = LoginForm() 199 | # if form.validate_on_submit(): 200 | # # login and validate the user... 201 | # login_user(user) 202 | # flash("Logged in successfully.", 'alert-success') 203 | # return redirect(url_for("user_box", the_user=user.name) or url_for("index")) 204 | return render_template("login.html", form=form) 205 | 206 | 207 | @app.route('/admin') 208 | @login_required 209 | @roles_required('admin') 210 | def admin(): 211 | containers = User.query.all() 212 | containers_list = [] 213 | for container in containers: 214 | uptime = DockerBackend.how_long_up(container.name) 215 | time_left = DockerBackend.check_if_over_time(container) 216 | time_left = DockerBackend.display_time(time_left) 217 | containers_list.append({'name': container.name, 'uptime': uptime, 'time_left': time_left}) 218 | return render_template('admin.html', containers=containers_list) 219 | 220 | 221 | @app.route('/demo', methods=["GET"]) 222 | def demonstration(): 223 | username = 'demo' + ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(10)) 224 | demo_user_object = user_datastore.create_user(email=username + '@demo.com', name=username, password='demo', dhbox_duration=3600) 225 | db.session.commit() 226 | login_user(demo_user_object) 227 | DockerBackend.demo_dhbox(username) 228 | return redirect('/dhbox/' + username) 229 | 230 | 231 | @app.route('/dhbox/') 232 | @login_required 233 | def user_box(the_user): 234 | which_user = User.query.filter(User.name == str(the_user)).first() 235 | if current_user.__name__ is 'AnonymousUser': 236 | return redirect(url_for("index")) 237 | if which_user is None or current_user is None: 238 | return redirect(url_for("index")) 239 | login_user(which_user) 240 | email_domain = which_user.email.split("@", 1)[1] 241 | if email_domain == 'demo.com': 242 | demo = True 243 | else: 244 | demo = False 245 | try: 246 | port_4000 = urllib2.urlopen(str(request.url) + '/website') 247 | port_4000 = True 248 | print "port 4000 website found" 249 | except Exception: 250 | print "no port 4000 site" 251 | port_4000 = False 252 | time_left = which_user.dhbox_duration - DockerBackend.how_long_up(which_user.name) 253 | time_left = DockerBackend.display_time(time_left) 254 | resp = make_response(render_template('dhbox.html', 255 | user=the_user, 256 | apps=filter(lambda app: app.get('hide', False) != True, all_apps), 257 | demo=demo, 258 | time_left=time_left, 259 | bootstrap_container='container-fluid', 260 | fixed_scroll='fixed_scroll', 261 | port_4000=port_4000 262 | ) 263 | ) 264 | return resp 265 | 266 | 267 | @app.route("/dhbox//") 268 | @login_required 269 | def app_box(the_user, app_name): 270 | which_user = User.query.filter(User.name == str(the_user)).first() 271 | dhbox_username = which_user.name 272 | if app_name == 'wordpress': 273 | app_port = get_app(app_name)['port'] 274 | port_info = DockerBackend.get_container_port(dhbox_username+'_wp', app_port) 275 | elif app_name == 'website': 276 | app_port = '4000' 277 | port_info = DockerBackend.get_container_port(dhbox_username, app_port) 278 | else: 279 | app_port = get_app(app_name)['port'] 280 | port_info = DockerBackend.get_container_port(dhbox_username, app_port) 281 | hostname = DockerBackend.get_hostname() 282 | location = hostname + ":" + port_info 283 | return redirect('http://' + location) 284 | 285 | 286 | @app.route('/new_dhbox', methods=['POST']) 287 | def new_dhbox(): 288 | data = {key: request.form.getlist(key)[0] for key in request.form.keys()} 289 | for key in data: 290 | users_dict = key 291 | users_dict = ast.literal_eval(users_dict) 292 | users = users_dict['users'] 293 | for user in users: 294 | if 'name' in user: 295 | if 'email' in user: # Then is DH Box admin 296 | name_check = User.query.filter(User.name == user['name']).first() 297 | email_check = User.query.filter(User.name == user['email']).first() 298 | if name_check or email_check: 299 | print "Username taken. Already has a DH Box." 300 | return str('failure') 301 | admin_user = user['name'] 302 | admin_email = user['email'] 303 | admin_pass = user['pass'] 304 | if user['duration'] == 'day': 305 | duration = 86400 306 | elif user['duration'] == 'week': 307 | duration = 604800 308 | else: 309 | duration = 2592000 310 | # if user['duration'] == 'week': 311 | # duration = 604800 312 | # elif user['duration'] == 'month': 313 | # duration = 2592000 314 | # else: 315 | # duration = 13148730 316 | admin_user_object = user_datastore.create_user(email=user['email'], name=user['name'], password=user['pass'], dhbox_duration=duration) 317 | db.session.commit() 318 | login_user(admin_user_object) 319 | the_new_dhbox = DockerBackend.setup_new_dhbox(admin_user, admin_pass, admin_email) 320 | return str('Successfully created a new DH Box.') 321 | 322 | 323 | @app.route('/kill_dhbox', methods=['POST']) 324 | @login_required 325 | def kill_dhbox(): 326 | the_next = request.form.get('next') 327 | user = request.form.get('user') 328 | print(user) 329 | if current_user.has_role("admin"): 330 | pass 331 | elif user != current_user.name: 332 | # If they're not an admin and they're trying to delete a user that isn't them, 333 | # return a Forbidden error. 334 | return abort(403) 335 | DockerBackend.kill_and_remove_user(user) 336 | flash(message='DH Box and username deleted.', category='alert-success') 337 | return redirect(url_for(the_next) or url_for("index")) 338 | 339 | 340 | def police(): 341 | if os.path.isfile('dhbox-docker.db'): 342 | print "policing" 343 | users = User.query.all() 344 | for user in users: 345 | DockerBackend.check_and_kill(user) 346 | all_containers = DockerBackend.all_containers() 347 | for container in all_containers: 348 | try: 349 | time_up = DockerBackend.how_long_up(container) 350 | info = DockerBackend.get_container_info(container) 351 | name = info['Name'][1:] 352 | if name.startswith('demo') and time_up > 3600: 353 | DockerBackend.kill_and_remove_user(name) 354 | except Exception, e: 355 | print "Tried to check container: ", container 356 | raise e 357 | 358 | 359 | def run_schedule(): 360 | while 1: 361 | schedule.run_pending() 362 | time.sleep(1) 363 | 364 | 365 | schedule.every(1).minutes.do(police) 366 | t = Thread(target=run_schedule) 367 | t.daemon = True 368 | t.start() 369 | 370 | if __name__ == '__main__': 371 | app.debug = app.config['TESTING'] 372 | # Make database if it doesn't exist 373 | if not os.path.exists('dhbox-docker.db'): 374 | db.create_all() 375 | create_user_and_role() 376 | # Bind to PORT if defined, otherwise default to 5000. 377 | port = int(os.environ.get('PORT', 5000)) 378 | app.run(host='0.0.0.0', port=port, threaded=True) 379 | -------------------------------------------------------------------------------- /dist/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/favicon.ico -------------------------------------------------------------------------------- /dist/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /dist/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /dist/static/images/britishlibrary-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/britishlibrary-logo.gif -------------------------------------------------------------------------------- /dist/static/images/cuny-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/cuny-logo.jpg -------------------------------------------------------------------------------- /dist/static/images/dhbox_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/dhbox_shell.png -------------------------------------------------------------------------------- /dist/static/images/dhsi-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/dhsi-logo.jpg -------------------------------------------------------------------------------- /dist/static/images/hilt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/hilt-logo.png -------------------------------------------------------------------------------- /dist/static/images/ipython-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/ipython-logo.png -------------------------------------------------------------------------------- /dist/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/logo.png -------------------------------------------------------------------------------- /dist/static/images/nypl-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/nypl-logo.jpg -------------------------------------------------------------------------------- /dist/static/images/omeka-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/omeka-logo.gif -------------------------------------------------------------------------------- /dist/static/images/rstudio-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/dist/static/images/rstudio-logo.png -------------------------------------------------------------------------------- /dist/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |

About

5 | 6 |
7 | 8 |

What is it?

9 | 10 | 11 |

DH Box is a laboratory in the cloud that can be deployed quickly and easily. It's simply accessed from any computer 12 | as long as you've got an internet connection and some contextual knowledge.

13 | 14 |
15 | 16 |

Ready-to-go configurations of Omeka, NLTK, IPython, R Studio, and Mallet are included in the DH Box 21 | platform. Through this praxis friendly environment, professors and students have instant classroom access to a cadre 22 | of gold-standard DH tools. Professors will be able to launch a DH computer lab in just a few minutes.

23 | 24 |
25 | 26 |

Why use it?

27 | 28 |

With DH Box, faculty have the freedom to integrate DH tools into their curriculum without relying on external server 29 | administration or having to deal with labor intensive software installations, firewalls, and operating system 30 | configurations.

31 | 32 |
33 | 34 |

DH Box is device agnostic so scholars can research wherever there's an internet connection.

35 | 36 |
37 | 38 |

Who is it ideal for?

39 | 40 |

DH Box is being developed for college faculty who have familiarity with DH tools like Omeka, NLTK, R Studio, and 41 | Mallet. Do you know what the command line is? Do you know what a server does?

42 | 43 |
44 | 45 |

If you're unfamiliar with any of the above, we recommend you engage with some other resources first. Here are several 46 | places we recommend exploring:

47 | 48 |
49 | 50 |

The Command Line the Hard Way by 51 | Zed Shaw

52 | 53 |

Computer 54 | processing terminology by the Apache Software Foundation

55 | 56 |

Programming Lessons by the 57 | Programming Historian

58 | 59 |

How did they make 60 | that? deconstructing DH projects by Miriam Posner

61 | 62 |
63 | 64 |
65 |
66 | 67 |

68 | 69 | 70 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/admin.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Administration

4 |
5 | 6 | 7 | 8 | 9 | 10 | {% if containers %} 11 | {%for container in containers%} 12 | 13 | 14 | 15 | 16 | 22 | 23 | {%endfor%} 24 | {%else%} 25 | No containers 26 | {% endif %} 27 |
OwnerTime UpTime LeftButton
{{container.name}}{{container.uptime}}{{container.time_left}} 17 |
18 | 19 | 20 | 21 |
28 |

Container Info

29 |
30 |
31 | {% if containers %}
32 |     {{containers}}
33 | {% endif %}
34 | 
35 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Contact

4 | 5 |
6 | 7 |

We've begun building a community of educators, librarians, and developers organized around increasing the utility of 8 | DH Box and DH tools in academia. We plan to add more tools and make improvements based on community input.

9 | 10 |

Questions or comments? We'd love to hear from you!

11 | 12 |

Email hello [at] dhbox [dot] 13 | org or find us on Twitter.

14 | 15 | 16 | 17 |

18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/dhbox.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |
5 |
6 | 15 | 16 |
17 |
18 |
19 | {%if demo%} 20 |
21 |

22 | This is a DEMONSTRATION DH Box 23 | 24 |

25 |
26 |

User/pass for all applications:

27 |

demonstration/demonstration

28 |
29 | {%endif%} 30 |
31 |
32 | 34 |

This is your DH Box's homepage.

35 |

User/pass for all applications is the same as for DH Box.

36 |

Your DH Box will expire in: {{time_left}}.

37 |

38 |
39 |
40 |
41 | {% for app in apps %} 42 | {% if app['port'] %} 43 |
44 | 45 |
46 | {% endif %} 47 | {% endfor %} 48 | {% if port_4000 %} 49 |
50 | 51 |
52 | {% else %} 53 |
54 | 55 |
56 | {% endif %} 57 |
58 |
59 |
60 |
61 | 62 | {% endblock %} 63 | 64 | 65 | -------------------------------------------------------------------------------- /dist/templates/get_started.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Get Started

4 | 5 |
6 | 7 |

DH Box is currently under development. Check our GitHub 8 | to see what's new.

9 | 10 |
11 | 12 | 13 | 14 | 15 |

16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |
5 |
6 |

7 | 9 |

{{institution}}

10 | 11 |

Setting up an environment for digital humanities computational work can be time-consuming 12 | and difficult. DH Box addresses this problem by streamlining installation processes and providing a 13 | digital humanities laboratory in the cloud through simple sign-in via a web browser.

14 |
15 | 16 |
17 | {% if demo %} 18 |
19 |
20 |
21 | Start Hour-Long Demo 22 |
23 |
24 |
25 | Sign Up 26 |
27 |
28 |
29 | Download from GitHub 30 |
31 |
32 | {% else %} 33 |
34 |
35 |
36 | Sign Up 37 |
38 |
39 |
40 | Download from GitHub 41 |
42 |
43 | {% endif %} 44 |
45 |
46 |
47 |

The DH Box platform comes pre-equipped with essential DH tools:

48 | 49 |

IPython, RStudio, Omeka, and NLTK.

50 |
51 |
52 |
53 |
54 | omeka 55 |
56 |
57 | ipython 58 |
59 |
60 | rstudio 61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |

DH Box is created in partnership with:

69 |
70 |
71 |
72 |
73 | British Library 74 |
75 |
76 | CUNY 77 |
78 |
79 | NYPL 80 |
81 |
82 | HILT 83 |
84 |
85 | dhsi.org 86 |
87 |
88 |
89 |
90 | {% endblock %} 91 | -------------------------------------------------------------------------------- /dist/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DH Box 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 67 |
68 |
69 | 70 | {% with messages = get_flashed_messages() %} 71 | {% if messages %} 72 |
73 | {% for message in messages %} 74 |
75 |
76 | 77 | {{message}} {{message.category}} 78 |
79 |
80 | {% endfor %} 81 |
82 | {% endif %} 83 | {% endwith %} 84 | 85 | {% block body %}{% endblock %} 86 |
87 | 89 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /dist/templates/news.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% filter markdown %} 4 | {% for news in news_list %} 5 |   6 | 7 |   8 | 9 | {{news}} 10 | {% endfor %} 11 | {% endfilter %} 12 | {% endblock %} 13 | 14 | 15 | -------------------------------------------------------------------------------- /dist/templates/our_team.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |

Our Team

5 |
6 |
7 |

Stephen Zweibel 8 | Lead Developer 9 |

10 |
11 |
12 |
13 |
14 |

Patrick Smyth 15 | Developer, Writer 16 |

17 |
18 |
19 |
20 |
21 |

Jojo Karlin 22 | Outreach Coordinator 23 |

24 |
25 |
26 |
27 |
28 |

Matthew K. Gold 29 | Academic Advisor 30 |

31 |
32 |
33 |
34 |
35 |
36 |

Other Contributors

37 |
38 |
39 |

Dennis Tenen 40 | Academic Advisor 41 |

42 |
43 |
44 |
45 |
46 |

Harlan Kellaway 47 | Project Alumni 48 |

49 |
50 |
51 |
52 |
53 |

Gioia Stevens 54 | Project Alumni 55 |

56 |
57 |
58 | 59 |
60 |
61 |

Evan Misshula 62 | Project Alumni 63 |

64 |
65 |
66 |
67 |
68 |

Micki Kaufman 69 | Project Alumni 70 |

71 |
72 |
73 |
74 |
75 |

Cailean Cooney 76 | Project Alumni 77 |

78 |
79 |
80 |
81 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/port.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DH Box 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 | 24 |

This tab will display anything on port 4000.

25 |
    26 |
  • Host: 0.0.0.0
  • 27 |
  • Port: 4000
  • 28 |
29 |

30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /dist/templates/security/login_user.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% from "security/_macros.html" import render_field_with_errors, render_field %} 4 | {% include "security/_messages.html" %} 5 | 37 | 38 | {% endblock %} -------------------------------------------------------------------------------- /dist/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 67 | {% endblock %} 68 | -------------------------------------------------------------------------------- /dist/templates/test.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 73 | 74 |
75 | 76 |

Launch a New DH Box

77 | 78 |
79 | 80 |

You're about to become the owner of a brand new DH Box.

81 | 82 |
83 | 84 | Just fill out the information below then click Launch. 85 | 86 |

87 | 88 |
89 | 90 |
91 | 92 |
93 |
94 |
95 |
96 | 97 | 99 | This is the user with complete control over a new DH Box. 100 |
101 |
102 | 103 | 105 | Passwords apply for access to: DH Box, Omeka, RStudio. 106 |
107 |
108 | 109 | 111 |
112 |
113 |
114 |
115 | 116 | Should anyone else - such as students - be able to access this DH Box? 117 | 118 |
119 | 120 | 123 |
124 |
125 | 126 |
127 | 128 |
129 |
130 | 131 |
132 | {% endblock %} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | useref = require('gulp-useref'), 3 | gulpif = require('gulp-if'), 4 | uglify = require('gulp-uglify'), 5 | minifyCss = require('gulp-minify-css'), 6 | del = require('del'), 7 | less = require('gulp-less'); 8 | 9 | gulp.task('clean', function () { 10 | del.sync(['dist']); 11 | }); 12 | 13 | gulp.task('useref', ['clean'], function () { 14 | var assets = useref.assets(); 15 | 16 | return gulp.src(['src/**/*.html', '!src/static/bower_components/**']) 17 | .pipe(assets) 18 | .pipe(gulpif('*.js', uglify())) 19 | .pipe(gulpif('*.css', less())) 20 | .pipe(assets.restore()) 21 | .pipe(useref()) 22 | .pipe(gulp.dest('dist')) 23 | }); 24 | 25 | gulp.task('copy-static', ['copy-images', 'copy-fonts', 'copy-other'], function () { 26 | 27 | }); 28 | 29 | gulp.task('copy-images', ['clean'], function () { 30 | return gulp.src('src/static/images/*') 31 | .pipe(gulp.dest('dist/static/images')); 32 | }); 33 | 34 | gulp.task('copy-fonts', ['clean'], function () { 35 | return gulp.src('src/static/fonts/*') 36 | .pipe(gulp.dest('dist/static/fonts')); 37 | }); 38 | 39 | 40 | gulp.task('copy-other', ['clean'], function () { 41 | return gulp.src('src/static/*') 42 | .pipe(gulp.dest('dist/static')); 43 | }); 44 | 45 | 46 | gulp.task('build', ['copy-static', 'useref'], function () { 47 | 48 | }); -------------------------------------------------------------------------------- /install_dhbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | apt-get update 3 | ret=`python -c 'import sys; print("%i" % (sys.hexversion<0x03000000))'` 4 | 5 | if [ $ret ]; then 6 | echo "Python exists" 7 | else 8 | echo "requires Python" 9 | exit 1 10 | fi 11 | if [ $ret -eq 0 ]; then 12 | echo "requires Python version < 3" 13 | exit 1 14 | else 15 | echo "Python version is < 3" 16 | fi 17 | apt-get install -y wget python-pip python-dev nodejs nodejs-legacy git build-essential checkinstall libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev npm 18 | 19 | wget -qO- https://get.docker.com/ | sh 20 | git clone https://github.com/DH-Box/dhbox.git 21 | cd ~/dhbox/ 22 | pip install -r requirements.txt 23 | sudo docker pull thedhbox/seed:latest 24 | # sudo docker pull thedhbox/twordpress 25 | sudo manage build_database 26 | ln -s /usr/bin/nodejs /usr/bin/node 27 | npm install -g bower gulp 28 | sudo -u ${USERNAME} bower install --allow-root --no-interactive 29 | echo "DH Box successfully installed!" 30 | # gulp build 31 | -------------------------------------------------------------------------------- /lamp-seed/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:trusty 2 | MAINTAINER Fernando Mayo , Feng Honglin 3 | 4 | # Install packages 5 | ENV DEBIAN_FRONTEND noninteractive 6 | RUN apt-get update && \ 7 | apt-get -y install supervisor git apache2 libapache2-mod-php5 mysql-server php5-mysql pwgen php-apc php5-mcrypt && \ 8 | echo "ServerName localhost" >> /etc/apache2/apache2.conf 9 | 10 | # Add image configuration and scripts 11 | ADD start-apache2.sh /start-apache2.sh 12 | ADD start-mysqld.sh /start-mysqld.sh 13 | ADD run.sh /run.sh 14 | RUN chmod 755 /*.sh 15 | ADD my.cnf /etc/mysql/conf.d/my.cnf 16 | ADD supervisord-apache2.conf /etc/supervisor/conf.d/supervisord-apache2.conf 17 | ADD supervisord-mysqld.conf /etc/supervisor/conf.d/supervisord-mysqld.conf 18 | 19 | # Remove pre-installed database 20 | RUN rm -rf /var/lib/mysql/* 21 | 22 | # Add MySQL utils 23 | ADD create_mysql_admin_user.sh /create_mysql_admin_user.sh 24 | RUN chmod 755 /*.sh 25 | 26 | # config to enable .htaccess 27 | ADD apache_default /etc/apache2/sites-available/000-default.conf 28 | RUN a2enmod rewrite 29 | 30 | # Configure /app folder with sample app 31 | RUN git clone https://github.com/fermayo/hello-world-lamp.git /app 32 | RUN mkdir -p /app && rm -fr /var/www/html && ln -s /app /var/www/html 33 | 34 | #Enviornment variables to configure php 35 | ENV PHP_UPLOAD_MAX_FILESIZE 10M 36 | ENV PHP_POST_MAX_SIZE 10M 37 | 38 | # Add volumes for MySQL 39 | # VOLUME ["/etc/mysql", "/var/lib/mysql" ] 40 | 41 | EXPOSE 80 3306 42 | CMD ["/run.sh"] 43 | -------------------------------------------------------------------------------- /lamp-seed/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /lamp-seed/README.md: -------------------------------------------------------------------------------- 1 | tutum-docker-lamp 2 | ================= 3 | 4 | [![Deploy to Tutum](https://s.tutum.co/deploy-to-tutum.svg)](https://dashboard.tutum.co/stack/deploy/) 5 | 6 | Out-of-the-box LAMP image (PHP+MySQL) 7 | 8 | 9 | Usage 10 | ----- 11 | 12 | To create the image `tutum/lamp`, execute the following command on the tutum-docker-lamp folder: 13 | 14 | docker build -t tutum/lamp . 15 | 16 | You can now push your new image to the registry: 17 | 18 | docker push tutum/lamp 19 | 20 | 21 | Running your LAMP docker image 22 | ------------------------------ 23 | 24 | Start your image binding the external ports 80 and 3306 in all interfaces to your container: 25 | 26 | docker run -d -p 80:80 -p 3306:3306 tutum/lamp 27 | 28 | Test your deployment: 29 | 30 | curl http://localhost/ 31 | 32 | Hello world! 33 | 34 | 35 | Loading your custom PHP application 36 | ----------------------------------- 37 | 38 | In order to replace the "Hello World" application that comes bundled with this docker image, 39 | create a new `Dockerfile` in an empty folder with the following contents: 40 | 41 | FROM tutum/lamp:latest 42 | RUN rm -fr /app && git clone https://github.com/username/customapp.git /app 43 | EXPOSE 80 3306 44 | CMD ["/run.sh"] 45 | 46 | replacing `https://github.com/username/customapp.git` with your application's GIT repository. 47 | After that, build the new `Dockerfile`: 48 | 49 | docker build -t username/my-lamp-app . 50 | 51 | And test it: 52 | 53 | docker run -d -p 80:80 -p 3306:3306 username/my-lamp-app 54 | 55 | Test your deployment: 56 | 57 | curl http://localhost/ 58 | 59 | That's it! 60 | 61 | 62 | Connecting to the bundled MySQL server from within the container 63 | ---------------------------------------------------------------- 64 | 65 | The bundled MySQL server has a `root` user with no password for local connections. 66 | Simply connect from your PHP code with this user: 67 | 68 | host_info; 71 | ?> 72 | 73 | 74 | Connecting to the bundled MySQL server from outside the container 75 | ----------------------------------------------------------------- 76 | 77 | The first time that you run your container, a new user `admin` with all privileges 78 | will be created in MySQL with a random password. To get the password, check the logs 79 | of the container by running: 80 | 81 | docker logs $CONTAINER_ID 82 | 83 | You will see an output like the following: 84 | 85 | ======================================================================== 86 | You can now connect to this MySQL Server using: 87 | 88 | mysql -uadmin -p47nnf4FweaKu -h -P 89 | 90 | Please remember to change the above password as soon as possible! 91 | MySQL user 'root' has no password but only allows local connections 92 | ======================================================================== 93 | 94 | In this case, `47nnf4FweaKu` is the password allocated to the `admin` user. 95 | 96 | You can then connect to MySQL: 97 | 98 | mysql -uadmin -p47nnf4FweaKu 99 | 100 | Remember that the `root` user does not allow connections from outside the container - 101 | you should use this `admin` user instead! 102 | 103 | 104 | Setting a specific password for the MySQL server admin account 105 | -------------------------------------------------------------- 106 | 107 | If you want to use a preset password instead of a random generated one, you can 108 | set the environment variable `MYSQL_PASS` to your specific password when running the container: 109 | 110 | docker run -d -p 80:80 -p 3306:3306 -e MYSQL_PASS="mypass" tutum/lamp 111 | 112 | You can now test your new admin password: 113 | 114 | mysql -uadmin -p"mypass" 115 | 116 | 117 | Disabling .htaccess 118 | -------------------- 119 | 120 | `.htaccess` is enabled by default. To disable `.htaccess`, you can remove the following contents from `Dockerfile` 121 | 122 | # config to enable .htaccess 123 | ADD apache_default /etc/apache2/sites-available/000-default.conf 124 | RUN a2enmod rewrite 125 | 126 | 127 | **by http://www.tutum.co** 128 | -------------------------------------------------------------------------------- /lamp-seed/apache_default: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin webmaster@localhost 3 | 4 | DocumentRoot /var/www/html 5 | 6 | Options FollowSymLinks 7 | AllowOverride None 8 | 9 | 10 | Options Indexes FollowSymLinks MultiViews 11 | # To make wordpress .htaccess work 12 | AllowOverride FileInfo 13 | Order allow,deny 14 | allow from all 15 | 16 | 17 | ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ 18 | 19 | AllowOverride None 20 | Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch 21 | Order allow,deny 22 | Allow from all 23 | 24 | 25 | ErrorLog ${APACHE_LOG_DIR}/error.log 26 | 27 | # Possible values include: debug, info, notice, warn, error, crit, 28 | # alert, emerg. 29 | LogLevel warn 30 | 31 | CustomLog ${APACHE_LOG_DIR}/access.log combined 32 | 33 | # 34 | # Set HTTPS environment variable if we came in over secure 35 | # channel. 36 | SetEnvIf x-forwarded-proto https HTTPS=on 37 | 38 | 39 | -------------------------------------------------------------------------------- /lamp-seed/create_mysql_admin_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /usr/bin/mysqld_safe > /dev/null 2>&1 & 4 | 5 | RET=1 6 | while [[ RET -ne 0 ]]; do 7 | echo "=> Waiting for confirmation of MySQL service startup" 8 | sleep 5 9 | mysql -uroot -e "status" > /dev/null 2>&1 10 | RET=$? 11 | done 12 | 13 | PASS=${MYSQL_PASS:-$(pwgen -s 12 1)} 14 | _word=$( [ ${MYSQL_PASS} ] && echo "preset" || echo "random" ) 15 | echo "=> Creating MySQL admin user with ${_word} password" 16 | 17 | mysql -uroot -e "CREATE USER 'admin'@'%' IDENTIFIED BY '$PASS'" 18 | mysql -uroot -e "GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION" 19 | 20 | 21 | echo "=> Done!" 22 | 23 | echo "========================================================================" 24 | echo "You can now connect to this MySQL Server using:" 25 | echo "" 26 | echo " mysql -uadmin -p$PASS -h -P" 27 | echo "" 28 | echo "Please remember to change the above password as soon as possible!" 29 | echo "MySQL user 'root' has no password but only allows local connections" 30 | echo "========================================================================" 31 | 32 | mysqladmin -uroot shutdown 33 | -------------------------------------------------------------------------------- /lamp-seed/my.cnf: -------------------------------------------------------------------------------- 1 | [mysqld] 2 | bind-address=0.0.0.0 3 | -------------------------------------------------------------------------------- /lamp-seed/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VOLUME_HOME="/var/lib/mysql" 4 | 5 | sed -ri -e "s/^upload_max_filesize.*/upload_max_filesize = ${PHP_UPLOAD_MAX_FILESIZE}/" \ 6 | -e "s/^post_max_size.*/post_max_size = ${PHP_POST_MAX_SIZE}/" /etc/php5/apache2/php.ini 7 | if [[ ! -d $VOLUME_HOME/mysql ]]; then 8 | echo "=> An empty or uninitialized MySQL volume is detected in $VOLUME_HOME" 9 | echo "=> Installing MySQL ..." 10 | mysql_install_db > /dev/null 2>&1 11 | echo "=> Done!" 12 | /create_mysql_admin_user.sh 13 | else 14 | echo "=> Using an existing volume of MySQL" 15 | fi 16 | 17 | exec supervisord -n 18 | -------------------------------------------------------------------------------- /lamp-seed/start-apache2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | source /etc/apache2/envvars 3 | exec apache2 -D FOREGROUND 4 | -------------------------------------------------------------------------------- /lamp-seed/start-mysqld.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exec mysqld_safe 3 | -------------------------------------------------------------------------------- /lamp-seed/supervisord-apache2.conf: -------------------------------------------------------------------------------- 1 | [program:apache2] 2 | command=/start-apache2.sh 3 | numprocs=1 4 | autostart=true 5 | autorestart=true -------------------------------------------------------------------------------- /lamp-seed/supervisord-mysqld.conf: -------------------------------------------------------------------------------- 1 | [program:mysqld] 2 | command=/start-mysqld.sh 3 | numprocs=1 4 | autostart=true 5 | autorestart=true -------------------------------------------------------------------------------- /lamp-seed/tutum.yml: -------------------------------------------------------------------------------- 1 | lamp: 2 | image: tutum/lamp 3 | ports: 4 | - 80:80 5 | - 3306:3306 6 | 7 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | from manager import Manager 2 | from docker import Client 3 | from docker.utils import kwargs_from_env 4 | import DockerBackend 5 | import dhbox 6 | import os 7 | from subprocess import call 8 | import docker.errors 9 | 10 | manager = Manager() 11 | 12 | 13 | @manager.command 14 | def new_seed(): 15 | """Build new seed for DH Box""" 16 | response = DockerBackend.build_dhbox() 17 | return response 18 | 19 | 20 | @manager.command 21 | def start(): 22 | """download seed for DH Box""" 23 | response = DockerBackend.download_dhbox() 24 | return response 25 | 26 | 27 | @manager.command 28 | def test(): 29 | """Build new test DH Box""" 30 | response = DockerBackend.setup_new_dhbox('test', 'password', 'test@gmail.com') 31 | return response 32 | 33 | 34 | @manager.command 35 | def start_over(): 36 | """Delete and make a new test DH Box""" 37 | cleanup() 38 | response = DockerBackend.kill_dhbox('test') 39 | response = DockerBackend.kill_dhbox('test_wp') 40 | DockerBackend.setup_new_dhbox('test', 'password', 'test@gmail.com') 41 | return response 42 | 43 | 44 | @manager.command 45 | def clean_slate(): 46 | """Delete all DH Boxes""" 47 | cleanup() 48 | response = DockerBackend.kill_dhbox('test') 49 | DockerBackend.setup_new_dhbox('test', 'password', 'test@gmail.com') 50 | return response 51 | 52 | 53 | @manager.command 54 | def killctr(ctr_name): 55 | """Delete a container""" 56 | print "killing container " + ctr_name 57 | response = DockerBackend.kill_dhbox(ctr_name) 58 | return response 59 | 60 | 61 | @manager.command 62 | def renew_admin(): 63 | """Updates admin's DH Box to the new seed.""" 64 | DockerBackend.replace_admin_dhbox_image() 65 | 66 | 67 | @manager.command 68 | def build_database(): 69 | """Builds website database and adds admin.""" 70 | if not os.path.exists('dhbox-docker.db'): 71 | print "Creating DH Box database" 72 | dhbox.db.create_all() 73 | dhbox.create_user_and_role() 74 | else: 75 | print "Database exists." 76 | 77 | 78 | @manager.command 79 | def cleanup(): 80 | """Delete ALL stopped containers, unnamed images""" 81 | print "Deleting stopped containers" 82 | call("docker ps -a | grep Exit | awk '{print $1}' | xargs docker rm", shell=True) 83 | print "Deleting images" 84 | delete_untagged() 85 | 86 | 87 | @manager.command 88 | def police(): 89 | """check for boxes over their time limit, kill them""" 90 | dhbox.police() 91 | 92 | 93 | def delete_untagged(): 94 | """Find the untagged images and remove them""" 95 | images = c.images() 96 | found = False 97 | for image in images: 98 | if image["RepoTags"] == [":"]: 99 | found = True 100 | image_id = image["Id"] 101 | print "Deleting untagged image\nhash=", image_id 102 | try: 103 | c.remove_image(image["Id"]) 104 | except docker.errors.APIError as error: 105 | print "Failed to delete image\nhash={}\terror={}", image_id, error 106 | if not found: 107 | print "Didn't find any untagged images to delete!" 108 | 109 | 110 | @manager.command 111 | def check_users(): 112 | """list all usernames and emails""" 113 | users = dhbox.User.query.all() 114 | for user in users: 115 | print user.name 116 | print user.email 117 | 118 | c = DockerBackend.attach_to_docker_client() 119 | 120 | if __name__ == '__main__': 121 | manager.main() -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dhbox", 3 | "version": "0.0.0", 4 | "description": "A push-button Digital Humanities laboratory.", 5 | "main": " ", 6 | "dependencies": { 7 | "bower": "~1.4.1", 8 | "gulp": "~3.8.11", 9 | "gulp-if": "~1.2.5", 10 | "gulp-minify-css": "~1.1.3", 11 | "gulp-uglify": "~1.2.0", 12 | "gulp-useref": "~1.2.0", 13 | "gulp-less": "~3.0.3", 14 | "del": "~1.2.0" 15 | }, 16 | "devDependencies": {}, 17 | "scripts": { 18 | "test": "echo \"Error: no test specified\" && exit 1" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/DH-Box/dhbox.git" 23 | }, 24 | "author": "", 25 | "bugs": { 26 | "url": "https://github.com/DH-Box/dhbox/issues" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.10.1 2 | Flask-Login==0.2.11 3 | Flask-Mail==0.9.1 4 | Flask-Markdown==0.3 5 | Flask-Principal==0.4.0 6 | Flask-SQLAlchemy==2.0 7 | Flask-Security==1.7.4 8 | Flask-WTF==0.10.3 9 | Jinja2==2.7.3 10 | Markdown==2.6.6 11 | MarkupSafe==0.23 12 | SQLAlchemy==0.9.8 13 | WTForms==2.0.1 14 | Werkzeug==0.9.6 15 | argparse==1.2.1 16 | backports.ssl-match-hostname==3.4.0.2 17 | blinker==1.3 18 | docker-py==1.5.0 19 | gevent==1.0.2 20 | greenlet==0.4.9 21 | gunicorn==19.3.0 22 | ipgetter==0.6 23 | itsdangerous==0.24 24 | manage.py==0.2.6 25 | passlib==1.6.2 26 | requests==2.8.1 27 | schedule==0.3.2 28 | six==1.10.0 29 | websocket-client==0.34.0 30 | wsgiref==0.1.2 31 | -------------------------------------------------------------------------------- /seed/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:0.9.18 2 | MAINTAINER Steve 3 | 4 | # Set correct environment variables. 5 | ENV HOME /root 6 | ENV DEBIAN_FRONTEND noninteractive 7 | 8 | ENV REFRESHED_AT 2018-04-30 9 | RUN groupadd dhbox 10 | 11 | RUN echo "deb http://cran.rstudio.com/bin/linux/ubuntu trusty/" >> /etc/apt/sources.list 12 | RUN apt-get -y update 13 | 14 | # General needs 15 | RUN curl -sL https://deb.nodesource.com/setup_5.x | sudo -E bash - 16 | RUN apt-get update 17 | RUN apt-get -qy install emacs git python-apt apt-utils software-properties-common sudo curl wget unzip opensmtpd nodejs libssl-dev libpam0g-dev zlib1g-dev dh-autoreconf automake autoconf build-essential 18 | # RUN apt-get install ipython-notebook python-pip python3-pip python-dev python3-dev python3-scipy python3-pandas python3-matplotlib python3-numpy 19 | 20 | RUN wget https://repo.continuum.io/archive/Anaconda3-4.1.1-Linux-x86_64.sh -O /anaconda.sh 21 | RUN bash /anaconda.sh -b -p /opt/anaconda 22 | ENV PATH /opt/anaconda/bin:$PATH 23 | ADD ./conda.sh /etc/profile.d/conda.sh 24 | RUN /opt/anaconda/bin/conda install pip 25 | RUN /opt/anaconda/bin/pip install paramiko 26 | RUN chmod 777 -R /opt/anaconda/ 27 | # For Wetty 28 | RUN npm install -g wetty 29 | 30 | WORKDIR / 31 | 32 | 33 | # For MALLET 34 | RUN apt-get -qy install default-jdk ant python3-pip 35 | RUN mkdir /mallet 36 | RUN wget -O /tmp/mallet.tar.gz http://mallet.cs.umass.edu/dist/mallet-2.0.7.tar.gz 37 | RUN tar xfz /tmp/mallet.tar.gz --strip-components=1 -C /mallet 38 | RUN ant -buildfile /mallet/build.xml 39 | 40 | # For Jupyter 41 | # RUN pip3 install jupyter 42 | # RUN add-apt-repository ppa:chris-lea/zeromq 43 | # RUN apt-get update 44 | # RUN apt-get -qy --force-yes install libzmq3-dbg libzmq3-dev libzmq3 littler 45 | # # Set default CRAN repo 46 | # RUN echo 'options("repos"="http://cran.rstudio.com")' >> /usr/lib/R/etc/Rprofile.site 47 | # # Install IRkernel 48 | # RUN Rscript -e "install.packages(c('rzmq','repr','IRkernel','IRdisplay'), repos = c('http://irkernel.github.io/', getOption('repos')))" -e "IRkernel::installspec()" 49 | 50 | # For NLTK 51 | # RUN apt-get -qy install python-numpy python-scipy python-matplotlib 52 | # RUN pip install NLTK 53 | 54 | # For R-Studio 55 | RUN apt-get -qy --force-yes install r-base r-base-dev gdebi-core libatlas3-base libapparmor1 apparmor-profiles libssl0.9.8 56 | RUN wget https://download2.rstudio.org/rstudio-server-1.0.143-amd64.deb -O rstudio.deb 57 | RUN yes | gdebi rstudio.deb 58 | RUN ln -s /etc/apparmor.d/rstudio-server /etc/apparmor.d/disable/ 59 | RUN echo "server-app-armor-enabled=0" >> /etc/rstudio/rserver.conf 60 | RUN echo "www-frame-origin=any" >> /etc/rstudio/rserver.conf 61 | 62 | # For brackets 63 | RUN npm install brackets -g 64 | # RUN npm install -g grunt-cli 65 | # # npm install -g node-inspector 66 | # RUN git clone https://github.com/rabchev/brackets-server.git 67 | # WORKDIR /brackets-server 68 | # RUN npm cache clean 69 | # RUN npm update -g 70 | # RUN git submodule update --init --recursive && \ 71 | # npm install && \ 72 | # grunt build 73 | WORKDIR / 74 | RUN apt-get -qy install apache2 mysql-server 75 | # For the file manager 76 | RUN npm install node-file-manager -g 77 | 78 | # Adding Deamons to containers 79 | RUN mkdir -p /etc/service/mysql 80 | ADD ./runit_scripts/mysql.sh /etc/service/mysql/run 81 | RUN chmod +x /etc/service/mysql/run 82 | 83 | RUN mkdir -p /etc/service/rserver 84 | ADD ./runit_scripts/rserver.sh /etc/service/rserver/run 85 | RUN chmod +x /etc/service/rserver/run 86 | 87 | RUN mkdir -p /etc/service/wetty 88 | ADD ./runit_scripts/wetty.sh /etc/service/wetty/run 89 | RUN chmod +x /etc/service/wetty/run 90 | 91 | RUN mkdir -p /etc/service/apache2 92 | ADD ./runit_scripts/apache2.sh /etc/service/apache2/run 93 | RUN chmod +x /etc/service/apache2/run 94 | 95 | RUN mkdir -p /etc/service/explorer 96 | ADD ./runit_scripts/explorer.sh /etc/service/explorer/run 97 | RUN chmod +x /etc/service/explorer/run 98 | 99 | RUN mkdir -p /etc/service/smtpd 100 | ADD ./runit_scripts/smtpd.sh /etc/service/smtpd/run 101 | RUN chmod +x /etc/service/smtpd/run 102 | 103 | RUN mkdir -p /etc/service/notebook 104 | ADD ./runit_scripts/notebook.sh /etc/service/notebook/run 105 | RUN chmod +x /etc/service/notebook/run 106 | 107 | RUN mkdir -p /etc/service/brackets 108 | ADD ./runit_scripts/brackets.sh /etc/service/brackets/run 109 | RUN chmod +x /etc/service/brackets/run 110 | 111 | # Fix smtpd purge error that creates millions of folders 112 | RUN mkdir -p /var/spool/smtpd/purge 113 | RUN chmod 775 /var/spool/smtpd/purge 114 | 115 | ##startup scripts 116 | RUN mkdir -p /etc/my_init.d 117 | ADD ./runit_scripts/startup.sh /etc/my_init.d/startup.sh 118 | RUN chmod +x /etc/my_init.d/startup.sh 119 | 120 | EXPOSE 22 25 8787 8081 8080 4000 4200 8888 121 | 122 | # Use baseimage-docker's init system. 123 | CMD ["/sbin/my_init"] 124 | -------------------------------------------------------------------------------- /seed/conda.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export PATH=$PATH:/opt/anaconda/bin 3 | source activate root -------------------------------------------------------------------------------- /seed/index.html: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | # 4 | # This script is meant for quick & easy install via: 5 | # 'curl -sSL https://get.docker.com/ | sh' 6 | # or: 7 | # 'wget -qO- https://get.docker.com/ | sh' 8 | # 9 | # 10 | # Docker Maintainers: 11 | # To update this script on https://get.docker.com, 12 | # use hack/release.sh during a normal release, 13 | # or the following one-liner for script hotfixes: 14 | # s3cmd put --acl-public -P hack/install.sh s3://get.docker.com/index 15 | # 16 | 17 | url='https://get.docker.com/' 18 | 19 | command_exists() { 20 | command -v "$@" > /dev/null 2>&1 21 | } 22 | 23 | echo_docker_as_nonroot() { 24 | your_user=your-user 25 | [ "$user" != 'root' ] && your_user="$user" 26 | # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-EOF", spaces are kept in the output 27 | cat <<-EOF 28 | 29 | If you would like to use Docker as a non-root user, you should now consider 30 | adding your user to the "docker" group with something like: 31 | 32 | sudo usermod -aG docker $your_user 33 | 34 | Remember that you will have to log out and back in for this to take effect! 35 | 36 | EOF 37 | } 38 | 39 | do_install() { 40 | case "$(uname -m)" in 41 | *64) 42 | ;; 43 | *) 44 | cat >&2 <<-'EOF' 45 | Error: you are not using a 64bit platform. 46 | Docker currently only supports 64bit platforms. 47 | EOF 48 | exit 1 49 | ;; 50 | esac 51 | 52 | if command_exists docker || command_exists lxc-docker; then 53 | cat >&2 <<-'EOF' 54 | Warning: "docker" or "lxc-docker" command appears to already exist. 55 | Please ensure that you do not already have docker installed. 56 | You may press Ctrl+C now to abort this process and rectify this situation. 57 | EOF 58 | ( set -x; sleep 20 ) 59 | fi 60 | 61 | user="$(id -un 2>/dev/null || true)" 62 | 63 | sh_c='sh -c' 64 | if [ "$user" != 'root' ]; then 65 | if command_exists sudo; then 66 | sh_c='sudo -E sh -c' 67 | elif command_exists su; then 68 | sh_c='su -c' 69 | else 70 | cat >&2 <<-'EOF' 71 | Error: this installer needs the ability to run commands as root. 72 | We are unable to find either "sudo" or "su" available to make this happen. 73 | EOF 74 | exit 1 75 | fi 76 | fi 77 | 78 | curl='' 79 | if command_exists curl; then 80 | curl='curl -sSL' 81 | elif command_exists wget; then 82 | curl='wget -qO-' 83 | elif command_exists busybox && busybox --list-modules | grep -q wget; then 84 | curl='busybox wget -qO-' 85 | fi 86 | 87 | # perform some very rudimentary platform detection 88 | lsb_dist='' 89 | if command_exists lsb_release; then 90 | lsb_dist="$(lsb_release -si)" 91 | fi 92 | if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then 93 | lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")" 94 | fi 95 | if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then 96 | lsb_dist='debian' 97 | fi 98 | if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then 99 | lsb_dist='fedora' 100 | fi 101 | if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then 102 | lsb_dist="$(. /etc/os-release && echo "$ID")" 103 | fi 104 | 105 | lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')" 106 | case "$lsb_dist" in 107 | amzn|fedora|centos) 108 | if [ "$lsb_dist" = 'amzn' ]; then 109 | ( 110 | set -x 111 | $sh_c 'sleep 3; yum -y -q install docker' 112 | ) 113 | else 114 | ( 115 | set -x 116 | $sh_c 'sleep 3; yum -y -q install docker-io' 117 | ) 118 | fi 119 | if command_exists docker && [ -e /var/run/docker.sock ]; then 120 | ( 121 | set -x 122 | $sh_c 'docker version' 123 | ) || true 124 | fi 125 | echo_docker_as_nonroot 126 | exit 0 127 | ;; 128 | 129 | ubuntu|debian|linuxmint) 130 | export DEBIAN_FRONTEND=noninteractive 131 | 132 | did_apt_get_update= 133 | apt_get_update() { 134 | if [ -z "$did_apt_get_update" ]; then 135 | ( set -x; $sh_c 'sleep 3; apt-get update' ) 136 | did_apt_get_update=1 137 | fi 138 | } 139 | 140 | # aufs is preferred over devicemapper; try to ensure the driver is available. 141 | if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then 142 | if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then 143 | kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual" 144 | 145 | apt_get_update 146 | ( set -x; $sh_c 'sleep 3; apt-get install -y -q '"$kern_extras" ) || true 147 | 148 | if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then 149 | echo >&2 'Warning: tried to install '"$kern_extras"' (for AUFS)' 150 | echo >&2 ' but we still have no AUFS. Docker may not work. Proceeding anyways!' 151 | ( set -x; sleep 10 ) 152 | fi 153 | else 154 | echo >&2 'Warning: current kernel is not supported by the linux-image-extra-virtual' 155 | echo >&2 ' package. We have no AUFS support. Consider installing the packages' 156 | echo >&2 ' linux-image-virtual kernel and linux-image-extra-virtual for AUFS support.' 157 | ( set -x; sleep 10 ) 158 | fi 159 | fi 160 | 161 | # install apparmor utils if they're missing and apparmor is enabled in the kernel 162 | # otherwise Docker will fail to start 163 | if [ "$(cat /sys/module/apparmor/parameters/enabled 2>/dev/null)" = 'Y' ]; then 164 | if command -v apparmor_parser &> /dev/null; then 165 | echo 'apparmor is enabled in the kernel and apparmor utils were already installed' 166 | else 167 | echo 'apparmor is enabled in the kernel, but apparmor_parser missing' 168 | apt_get_update 169 | ( set -x; $sh_c 'sleep 3; apt-get install -y -q apparmor' ) 170 | fi 171 | fi 172 | 173 | if [ ! -e /usr/lib/apt/methods/https ]; then 174 | apt_get_update 175 | ( set -x; $sh_c 'sleep 3; apt-get install -y -q apt-transport-https ca-certificates' ) 176 | fi 177 | if [ -z "$curl" ]; then 178 | apt_get_update 179 | ( set -x; $sh_c 'sleep 3; apt-get install -y -q curl ca-certificates' ) 180 | curl='curl -sSL' 181 | fi 182 | ( 183 | set -x 184 | if [ "https://get.docker.com/" = "$url" ]; then 185 | $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9" 186 | elif [ "https://test.docker.com/" = "$url" ]; then 187 | $sh_c "apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 740B314AE3941731B942C66ADF4FD13717AAD7D6" 188 | else 189 | $sh_c "$curl ${url}gpg | apt-key add -" 190 | fi 191 | $sh_c "echo deb ${url}ubuntu docker main > /etc/apt/sources.list.d/docker.list" 192 | $sh_c 'sleep 3; apt-get update; apt-get install -y -q lxc-docker' 193 | ) 194 | if command_exists docker && [ -e /var/run/docker.sock ]; then 195 | ( 196 | set -x 197 | $sh_c 'docker version' 198 | ) || true 199 | fi 200 | echo_docker_as_nonroot 201 | exit 0 202 | ;; 203 | 204 | gentoo) 205 | if [ "$url" = "https://test.docker.com/" ]; then 206 | # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output 207 | cat >&2 <<-'EOF' 208 | 209 | You appear to be trying to install the latest nightly build in Gentoo.' 210 | The portage tree should contain the latest stable release of Docker, but' 211 | if you want something more recent, you can always use the live ebuild' 212 | provided in the "docker" overlay available via layman. For more' 213 | instructions, please see the following URL:' 214 | 215 | https://github.com/tianon/docker-overlay#using-this-overlay' 216 | 217 | After adding the "docker" overlay, you should be able to:' 218 | 219 | emerge -av =app-emulation/docker-9999' 220 | 221 | EOF 222 | exit 1 223 | fi 224 | 225 | ( 226 | set -x 227 | $sh_c 'sleep 3; emerge app-emulation/docker' 228 | ) 229 | exit 0 230 | ;; 231 | esac 232 | 233 | # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output 234 | cat >&2 <<-'EOF' 235 | 236 | Either your platform is not easily detectable, is not supported by this 237 | installer script (yet - PRs welcome! [hack/install.sh]), or does not yet have 238 | a package for Docker. Please visit the following URL for more detailed 239 | installation instructions: 240 | 241 | https://docs.docker.com/en/latest/installation/ 242 | 243 | EOF 244 | exit 1 245 | } 246 | 247 | # wrapped up in a function so that we have some protection against only getting 248 | # half the file during "curl | sh" 249 | do_install 250 | -------------------------------------------------------------------------------- /seed/omeka/config.ini: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; Site Configuration File ; 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | ; 5 | ; Lower-level settings for Omeka are defined here. 6 | ; 7 | ; The default settings should be correct for most Omeka users, but some 8 | ; setups may require some changes. People who are developing for or 9 | ; debugging Omeka may also change some of these settings. 10 | 11 | [site] 12 | 13 | ;;;;;;;;;;;;;;;; 14 | ; Localization ; 15 | ;;;;;;;;;;;;;;;; 16 | 17 | ; locale.name 18 | ; The locale identifier used for translating and displaying Omeka. 19 | ; default: none 20 | ; 21 | ; The locale controls what language Omeka will be displayed in, and 22 | ; also how dates and other locale-sensitive data will be displayed. 23 | ; 24 | ; The locale identifier should be a valid ISO 639 language code, 25 | ; and optionally a valid ISO 3166-1 locale code. 26 | ; (Examples: "es" for Spanish, "en_US" for US English.) 27 | ; 28 | ; To enable translations, the identifier must also have a 29 | ; corresponding .mo file in the application/languages directory. 30 | 31 | locale.name = "" 32 | 33 | ;;;;;;;;;;;;; 34 | ; Debugging ; 35 | ;;;;;;;;;;;;; 36 | 37 | ; debug.exceptions 38 | ; Throw exceptions for bad URLs. 39 | ; default: false 40 | ; 41 | ; This should only be enabled when debugging or developing for Omeka. 42 | debug.exceptions = false 43 | 44 | ; debug.request 45 | ; Dump data about each web request to the browser. 46 | ; default: false 47 | ; 48 | ; The request data shows what routes and variables Omeka has parsed from 49 | ; each request. 50 | debug.request = false 51 | 52 | ; debug.profileDb 53 | ; Enable the query profiler. 54 | ; default: false 55 | ; 56 | ; This will show metadata about the queries that were executed during 57 | ; each request. 58 | debug.profileDb = false 59 | 60 | ; debug.email 61 | ; Send all log messages to an email address. 62 | ; default: "" 63 | ; 64 | ; Anything that would be logged will also be emailed to this address. 65 | ; If left blank, this feature is disabled. 66 | debug.email = "" 67 | 68 | ; debug.emailLogPriority 69 | ; Apply a priority filter to emailed log messages. 70 | ; default: Zend_Log::ERR 71 | ; 72 | ; If an address has been set for debug.email, this setting filters the 73 | ; messages to only those of the given priority or higher. 74 | debug.emailLogPriority = Zend_Log::ERR 75 | 76 | ;;;;;;;;;;; 77 | ; Logging ; 78 | ;;;;;;;;;;; 79 | 80 | ; log.errors 81 | ; Log errors and other information. 82 | ; default: false 83 | ; 84 | ; Errors, exceptions, and other messages will be logged to 85 | ; application/logs/errors.log (this file must be writable by the web 86 | ; server if logging is enabled). 87 | log.errors = false 88 | 89 | ; log.priority 90 | ; The minimum priority level of messages that should be logged. 91 | ; When developing/debugging, use Zend_Log::DEBUG for debug() to work. This will record everything. 92 | ; default: Zend_Log::WARN (Logs warnings and above) 93 | log.priority = Zend_Log::WARN 94 | 95 | ; log.sql 96 | ; Log SQL statements. 97 | ; default: false 98 | ; 99 | ; All SQL statements executed by Omeka will be included in Omeka's 100 | ; error log. 101 | log.sql = false 102 | 103 | ;;;;;;;;;;;; 104 | ; Sessions ; 105 | ;;;;;;;;;;;; 106 | ; 107 | ; Omeka uses Zend Framework's session handling. A full list of 108 | ; available session configuration options can be found here: 109 | ; http://framework.zend.com/manual/en/zend.session.global_session_management.html#zend.session.global_session_management.configuration_options 110 | ; 111 | ; Some options that are often useful for Omeka sites are included here. 112 | 113 | ; session.name 114 | ; Sets the name used for the Omeka session cookie. 115 | ; default: "" 116 | ; 117 | ; If left blank, Omeka will automatically select a unique session name. 118 | session.name = "" 119 | 120 | ; session.saveHandler 121 | ; Determines how session data will be saved. 122 | ; default: no setting (uses the database for saving session data) 123 | ; 124 | ; Sessions are now stored in the database by default. To revert to the 125 | ; older method of storing session data in the filesystem, uncomment the 126 | ; following line. 127 | ; session.saveHandler = "" 128 | 129 | ;;;;;;;;; 130 | ; Theme ; 131 | ;;;;;;;;; 132 | 133 | ; theme.useInternalAssets 134 | ; Whether Omeka should use locally-stored asset files. 135 | ; default: false 136 | ; 137 | ; Omeka includes some asset files from external sources, such as Google by 138 | ; default. Set this to true if the Omeka installation does not have 139 | ; web access, and Omeka will instead serve local copies of these files. 140 | theme.useInternalAssets = false 141 | 142 | ;;;;;;;;;;;;;;;;;;;;;; 143 | ; Background Scripts ; 144 | ;;;;;;;;;;;;;;;;;;;;;; 145 | 146 | ; background.php.path 147 | ; Path to PHP-CLI for running background processes. 148 | ; default: "" 149 | ; 150 | ; If left blank, Omeka will try to autodetect the right path. Set this 151 | ; to override the autodetected PHP path. 152 | background.php.path = "" 153 | 154 | ; jobs.dispatcher 155 | ; How Omeka "jobs" will be executed. 156 | ; default: "Omeka_Job_Dispatcher_Adapter_Synchronous" 157 | ; 158 | ; Newer Omeka features and plugins use this setting to determine how 159 | ; long-running jobs will be run. 160 | ; 161 | ; The default setting should work for all installations, but may 162 | ; time out for longer jobs. On systems where the older PHP background 163 | ; processes worked, the BackgroundProcess adapter can be used instead 164 | ; of the Synchronous one. 165 | jobs.dispatcher.default = "Omeka_Job_Dispatcher_Adapter_Synchronous" 166 | jobs.dispatcher.longRunning = "Omeka_Job_Dispatcher_Adapter_BackgroundProcess" 167 | 168 | ;;;;;;;; 169 | ; Mail ; 170 | ;;;;;;;; 171 | ; 172 | ; For more info, see Zend Framework documentation on Zend_Mail: 173 | ; http://framework.zend.com/manual/en/zend.mail.html 174 | 175 | ; mail.transport.type 176 | ; The system Omeka will use to send email messages. 177 | ; default: "Sendmail" 178 | ; 179 | ; The default is to send mail using PHP's built-in mail() function. 180 | mail.transport.type = "Sendmail" 181 | 182 | ; Uncomment some of the following lines (and comment the above line) 183 | ; to switch to SMTP for sending mail through Omeka. Your configuration 184 | ; may not require all of the options listed. 185 | ; 186 | ; mail.transport.type = "Smtp" 187 | ; mail.transport.host = "" 188 | ; mail.transport.port = ### ; Port number, if applicable. 189 | ; mail.transport.name = "" ; Local client hostname, e.g. "localhost" 190 | ; mail.transport.auth = "login" ; For authentication, if required. 191 | ; mail.transport.username = "" 192 | ; mail.transport.password = "" 193 | ; mail.transport.ssl = "" ; For SSL support, set to "ssl" or "tls" 194 | 195 | ; Sample S3 cloud storage configuration 196 | ; 197 | ; The accessKeyId, secretAccessKey, and bucket options are all required. 198 | ; If the expiration option is set, files will be uploaded with "private" 199 | ; access, and Omeka will generate URLs that are only valid for a limited 200 | ; time. If the expiration option is missing or left commented out, 201 | ; uploaded files will always be publicly readable. 202 | ; 203 | ; storage.adapter = "Omeka_Storage_Adapter_ZendS3" 204 | ; storage.adapterOptions.accessKeyId = 205 | ; storage.adapterOptions.secretAccessKey = 206 | ; storage.adapterOptions.bucket = 207 | ; storage.adapterOptions.expiration = 10 ; URL expiration time (in minutes) 208 | ; storage.adapterOptions.endpoint = ; Custom S3 endpoint (optional) 209 | 210 | ;;;;;;;;;;;; 211 | ; Security ; 212 | ;;;;;;;;;;;; 213 | 214 | ; ssl 215 | ; Secure Socket Layer support for Omeka. 216 | ; default: none 217 | ; 218 | ; Ensure that your server is properly configured before enabling this 219 | ; setting. Choose one of the following: 220 | ; 221 | ; "logins" 222 | ; Force SSL for login forms and login form submissions. 223 | ; 224 | ; "sessions" 225 | ; Force SSL for all authenticated users to protect sessions. Includes 226 | ; login forms. 227 | ; 228 | ; "always" 229 | ; Force SSL on across the entire site. 230 | ; 231 | ; ssl = "always" 232 | 233 | ;;;;;;;;;; 234 | ; Upload ; 235 | ;;;;;;;;;; 236 | 237 | ; upload.maxFileSize 238 | ; Set the maximum file upload size. 239 | ; default: 10M 240 | ; 241 | ; Uncomment the following line to set the maximum file upload size. This 242 | ; configuration will not exceed the maximum beyond what is set in the 243 | ; 'post_max_size' or 'upload_max_filesize' core php.ini directives. 244 | ; 245 | ;upload.maxFileSize = "10M" 246 | -------------------------------------------------------------------------------- /seed/omeka/db.ini: -------------------------------------------------------------------------------- 1 | [database] 2 | host = "localhost" 3 | username = "omeka" 4 | password = "omeka" 5 | dbname = "omeka" 6 | prefix = "omeka" 7 | charset = "utf8" 8 | ; port = "" 9 | -------------------------------------------------------------------------------- /seed/omeka/htaccess: -------------------------------------------------------------------------------- 1 | # Omeka .htaccess: Apache configuration file 2 | # This file is required for Omeka to function correctly. 3 | 4 | # --------------- # 5 | # Error Reporting # 6 | # --------------- # 7 | 8 | # Uncomment the SetEnv line below to turn on detailed on-screen error 9 | # reporting. 10 | # 11 | # Note: This should only be enabled for development or debugging. Keep this 12 | # line commented for production sites. 13 | # 14 | SetEnv APPLICATION_ENV development 15 | 16 | # ------------- # 17 | # Rewrite Rules # 18 | # ------------- # 19 | 20 | RewriteEngine on 21 | 22 | # If you know mod_rewrite is enabled, but you are still getting mod_rewrite 23 | # errors, uncomment the line below and replace "/" with your base directory. 24 | # 25 | # RewriteBase / 26 | 27 | # Allow direct access to files (except PHP files) 28 | RewriteCond %{REQUEST_FILENAME} -f 29 | RewriteRule !\.(php[0-9]?|phtml|phps)$ - [C] 30 | RewriteRule .* - [L] 31 | 32 | RewriteRule ^install/.*$ install/install.php [L] 33 | RewriteRule ^admin/.*$ admin/index.php [L] 34 | RewriteRule .* index.php 35 | 36 | # -------------- # 37 | # Access Control # 38 | # -------------- # 39 | 40 | # Block access to all .ini files. 41 | 42 | Order Allow,Deny 43 | Deny from all 44 | 45 | 46 | # --------# 47 | # Caching # 48 | # --------# 49 | 50 | # Uncomment the lines below in order to enable caching of some files 51 | # (after a finished site has gone live) 52 | # 53 | # 54 | # 55 | # ExpiresActive on 56 | # ExpiresDefault "access plus 10 day" 57 | # 58 | # 59 | 60 | # ------------ # 61 | # PHP Settings # 62 | # ------------ # 63 | 64 | 65 | php_flag register_globals off 66 | php_flag magic_quotes_gpc off 67 | -------------------------------------------------------------------------------- /seed/omeka/omeka.conf: -------------------------------------------------------------------------------- 1 | Listen 8080 2 | NameVirtualHost *:8080 3 | 4 | # The ServerName directive sets the request scheme, hostname and port that 5 | # the server uses to identify itself. This is used when creating 6 | # redirection URLs. In the context of virtual hosts, the ServerName 7 | # specifies what hostname must appear in the request's Host: header to 8 | # match this virtual host. For the default virtual host (this file) this 9 | # value is not decisive as it is used as a last resort host regardless. 10 | # However, you must set it for any further virtual host explicitly. 11 | #ServerName www.example.com 12 | 13 | ServerAdmin webmaster@localhost 14 | DocumentRoot /var/www/omeka 15 | 16 | Options FollowSymLinks 17 | AllowOverride All 18 | 19 | 20 | Options Indexes FollowSymLinks MultiViews 21 | AllowOverride All 22 | Order allow,deny 23 | Allow from all 24 | 25 | 26 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 27 | # error, crit, alert, emerg. 28 | # It is also possible to configure the loglevel for particular 29 | # modules, e.g. 30 | #LogLevel info ssl:warn 31 | 32 | ErrorLog ${APACHE_LOG_DIR}/error.log 33 | CustomLog ${APACHE_LOG_DIR}/access.log combined 34 | 35 | # For most configuration files from conf-available/, which are 36 | # enabled or disabled at a global level, it is possible to 37 | # include a line for only one particular virtual host. For example the 38 | # following line enables the CGI configuration for this host only 39 | # after it has been globally disabled with "a2disconf". 40 | #Include conf-available/serve-cgi-bin.conf 41 | 42 | -------------------------------------------------------------------------------- /seed/omeka/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # - include: tasks/install.yml 3 | # - include: tasks/config.yml 4 | # - include: tasks/db.yml 5 | # - include: tasks/apache.yml 6 | # - include: tasks/omeka.yml -------------------------------------------------------------------------------- /seed/omeka/tasks/apache.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: omeka config 3 | template: dest=/etc/apache2/sites-available/000-omeka.conf 4 | src=omeka.conf.j2 5 | sudo: true 6 | # - name: disable default site 7 | # command: a2dissite default 8 | # sudo: true 9 | # notify: 10 | # - restart apache2 11 | - name: a2ensite omeka 12 | command: a2ensite 000-omeka.conf 13 | sudo: true 14 | notify: 15 | - restart apache2 16 | # - name: Weirdness 17 | # command: sudo mkdir /run/lock 18 | # sudo: true 19 | # notify: 20 | # - restart apache2 21 | - name: a2enmod rewrite 22 | command: a2enmod rewrite 23 | sudo: true 24 | notify: 25 | - restart apache2 26 | - service: name=apache2 state=started 27 | -------------------------------------------------------------------------------- /seed/omeka/tasks/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: 10-fix_pathinfo.ini 3 | sudo: true 4 | copy: dest=/etc/php5/apache2/conf.d/10-fix_pathinfo.ini 5 | content='cgi.fix_pathinfo=0' 6 | -------------------------------------------------------------------------------- /seed/omeka/tasks/db.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: apt-get python-mysqldb 3 | sudo: true 4 | apt: pkg=python-mysqldb state=latest 5 | - name: Start the MySQL service 6 | action: service name=mysql state=started 7 | - name: clear omeka user 8 | mysql_user: name=omeka state=absent 9 | - name: create omeka user 10 | mysql_user: name=omeka password=omeka state=present priv=*.*:ALL 11 | - name: create omeka db 12 | mysql_db: name=omeka login_user=omeka login_password=omeka state=present 13 | -------------------------------------------------------------------------------- /seed/omeka/tasks/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: install Omeka apt packages 3 | apt: pkg={{ item }} state=latest 4 | sudo: true 5 | with_items: 6 | - apache2 7 | - php5 8 | - rsync 9 | - mysql-server 10 | - php5-mysql 11 | - imagemagick 12 | -------------------------------------------------------------------------------- /seed/omeka/tasks/omeka.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: db.ini 3 | template: src=db.ini.j2 dest={{ omekadir }}/db.ini 4 | sudo: true 5 | - name: chmod db.ini 6 | file: path={{ omekadir }}/db.ini mode=0666 7 | - name: cp config.ini 8 | template: src=config.ini dest={{ omekadir }}/application/config/config.ini 9 | # - name: config.ini debug 10 | # ini_file: dest={{ omekadir }}/application/config/config.ini 11 | # section=site 12 | # option=debug.exceptions 13 | # value={{ debug }} 14 | # - name: cp tests/config.ini 15 | # command: cp {{ omekadir }}/application/tests/config.ini {{ omekadir }}/application/tests/config.ini 16 | # - name: tests/config.ini db.username 17 | # ini_file: dest={{ omekadir }}/application/tests/config.ini 18 | # section=testing 19 | # option=db.username 20 | # value=omeka 21 | # - name: tests/config.ini db.password 22 | # ini_file: dest={{ omekadir }}/application/tests/config.ini 23 | # section=testing 24 | # option=db.password 25 | # value=omeka 26 | # - name: tests/config.ini db.dbname 27 | # ini_file: dest={{ omekadir }}/application/tests/config.ini 28 | # section=testing 29 | # option=db.dbname 30 | # value=omeka 31 | # - name: .htaccess 32 | # template: src=.htaccess dest={{ omekadir }}/.htaccess 33 | - name: APPLICATION_ENV 34 | lineinfile: dest={{ omekadir }}/.htaccess 35 | backrefs=yes 36 | regexp='# (SetEnv APPLICATION_ENV .*)' 37 | line='\1' 38 | - name: files 39 | file: path={{ omekadir }}/files recurse=yes mode=0777 40 | - name: hostname 41 | lineinfile: line='127.0.0.1 {{ hostname }}' state=present insertafter=EOF dest=/etc/hosts 42 | sudo: true 43 | when: hostname is defined 44 | -------------------------------------------------------------------------------- /seed/omeka/templates/config.ini: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 2 | ; Site Configuration File ; 3 | ;;;;;;;;;;;;;;;;;;;;;;;;;;; 4 | ; 5 | ; Lower-level settings for Omeka are defined here. 6 | ; 7 | ; The default settings should be correct for most Omeka users, but some 8 | ; setups may require some changes. People who are developing for or 9 | ; debugging Omeka may also change some of these settings. 10 | 11 | [site] 12 | 13 | ;;;;;;;;;;;;;;;; 14 | ; Localization ; 15 | ;;;;;;;;;;;;;;;; 16 | 17 | ; locale.name 18 | ; The locale identifier used for translating and displaying Omeka. 19 | ; default: none 20 | ; 21 | ; The locale controls what language Omeka will be displayed in, and 22 | ; also how dates and other locale-sensitive data will be displayed. 23 | ; 24 | ; The locale identifier should be a valid ISO 639 language code, 25 | ; and optionally a valid ISO 3166-1 locale code. 26 | ; (Examples: "es" for Spanish, "en_US" for US English.) 27 | ; 28 | ; To enable translations, the identifier must also have a 29 | ; corresponding .mo file in the application/languages directory. 30 | 31 | locale.name = "" 32 | 33 | ;;;;;;;;;;;;; 34 | ; Debugging ; 35 | ;;;;;;;;;;;;; 36 | 37 | ; debug.exceptions 38 | ; Throw exceptions for bad URLs. 39 | ; default: false 40 | ; 41 | ; This should only be enabled when debugging or developing for Omeka. 42 | debug.exceptions = false 43 | 44 | ; debug.request 45 | ; Dump data about each web request to the browser. 46 | ; default: false 47 | ; 48 | ; The request data shows what routes and variables Omeka has parsed from 49 | ; each request. 50 | debug.request = false 51 | 52 | ; debug.profileDb 53 | ; Enable the query profiler. 54 | ; default: false 55 | ; 56 | ; This will show metadata about the queries that were executed during 57 | ; each request. 58 | debug.profileDb = false 59 | 60 | ; debug.email 61 | ; Send all log messages to an email address. 62 | ; default: "" 63 | ; 64 | ; Anything that would be logged will also be emailed to this address. 65 | ; If left blank, this feature is disabled. 66 | debug.email = "" 67 | 68 | ; debug.emailLogPriority 69 | ; Apply a priority filter to emailed log messages. 70 | ; default: Zend_Log::ERR 71 | ; 72 | ; If an address has been set for debug.email, this setting filters the 73 | ; messages to only those of the given priority or higher. 74 | debug.emailLogPriority = Zend_Log::ERR 75 | 76 | ;;;;;;;;;;; 77 | ; Logging ; 78 | ;;;;;;;;;;; 79 | 80 | ; log.errors 81 | ; Log errors and other information. 82 | ; default: false 83 | ; 84 | ; Errors, exceptions, and other messages will be logged to 85 | ; application/logs/errors.log (this file must be writable by the web 86 | ; server if logging is enabled). 87 | log.errors = false 88 | 89 | ; log.priority 90 | ; The minimum priority level of messages that should be logged. 91 | ; When developing/debugging, use Zend_Log::DEBUG for debug() to work. This will record everything. 92 | ; default: Zend_Log::WARN (Logs warnings and above) 93 | log.priority = Zend_Log::WARN 94 | 95 | ; log.sql 96 | ; Log SQL statements. 97 | ; default: false 98 | ; 99 | ; All SQL statements executed by Omeka will be included in Omeka's 100 | ; error log. 101 | log.sql = false 102 | 103 | ;;;;;;;;;;;; 104 | ; Sessions ; 105 | ;;;;;;;;;;;; 106 | ; 107 | ; Omeka uses Zend Framework's session handling. A full list of 108 | ; available session configuration options can be found here: 109 | ; http://framework.zend.com/manual/en/zend.session.global_session_management.html#zend.session.global_session_management.configuration_options 110 | ; 111 | ; Some options that are often useful for Omeka sites are included here. 112 | 113 | ; session.name 114 | ; Sets the name used for the Omeka session cookie. 115 | ; default: "" 116 | ; 117 | ; If left blank, Omeka will automatically select a unique session name. 118 | session.name = "" 119 | 120 | ; session.saveHandler 121 | ; Determines how session data will be saved. 122 | ; default: no setting (uses the database for saving session data) 123 | ; 124 | ; Sessions are now stored in the database by default. To revert to the 125 | ; older method of storing session data in the filesystem, uncomment the 126 | ; following line. 127 | ; session.saveHandler = "" 128 | 129 | ;;;;;;;;; 130 | ; Theme ; 131 | ;;;;;;;;; 132 | 133 | ; theme.useInternalAssets 134 | ; Whether Omeka should use locally-stored asset files. 135 | ; default: false 136 | ; 137 | ; Omeka includes some asset files from external sources, such as Google by 138 | ; default. Set this to true if the Omeka installation does not have 139 | ; web access, and Omeka will instead serve local copies of these files. 140 | theme.useInternalAssets = false 141 | 142 | ;;;;;;;;;;;;;;;;;;;;;; 143 | ; Background Scripts ; 144 | ;;;;;;;;;;;;;;;;;;;;;; 145 | 146 | ; background.php.path 147 | ; Path to PHP-CLI for running background processes. 148 | ; default: "" 149 | ; 150 | ; If left blank, Omeka will try to autodetect the right path. Set this 151 | ; to override the autodetected PHP path. 152 | background.php.path = "" 153 | 154 | ; jobs.dispatcher 155 | ; How Omeka "jobs" will be executed. 156 | ; default: "Omeka_Job_Dispatcher_Adapter_Synchronous" 157 | ; 158 | ; Newer Omeka features and plugins use this setting to determine how 159 | ; long-running jobs will be run. 160 | ; 161 | ; The default setting should work for all installations, but may 162 | ; time out for longer jobs. On systems where the older PHP background 163 | ; processes worked, the BackgroundProcess adapter can be used instead 164 | ; of the Synchronous one. 165 | jobs.dispatcher.default = "Omeka_Job_Dispatcher_Adapter_Synchronous" 166 | jobs.dispatcher.longRunning = "Omeka_Job_Dispatcher_Adapter_BackgroundProcess" 167 | 168 | ;;;;;;;; 169 | ; Mail ; 170 | ;;;;;;;; 171 | ; 172 | ; For more info, see Zend Framework documentation on Zend_Mail: 173 | ; http://framework.zend.com/manual/en/zend.mail.html 174 | 175 | ; mail.transport.type 176 | ; The system Omeka will use to send email messages. 177 | ; default: "Sendmail" 178 | ; 179 | ; The default is to send mail using PHP's built-in mail() function. 180 | mail.transport.type = "Sendmail" 181 | 182 | ; Uncomment some of the following lines (and comment the above line) 183 | ; to switch to SMTP for sending mail through Omeka. Your configuration 184 | ; may not require all of the options listed. 185 | ; 186 | ; mail.transport.type = "Smtp" 187 | ; mail.transport.host = "" 188 | ; mail.transport.port = ### ; Port number, if applicable. 189 | ; mail.transport.name = "" ; Local client hostname, e.g. "localhost" 190 | ; mail.transport.auth = "login" ; For authentication, if required. 191 | ; mail.transport.username = "" 192 | ; mail.transport.password = "" 193 | ; mail.transport.ssl = "" ; For SSL support, set to "ssl" or "tls" 194 | 195 | ; Sample S3 cloud storage configuration 196 | ; 197 | ; The accessKeyId, secretAccessKey, and bucket options are all required. 198 | ; If the expiration option is set, files will be uploaded with "private" 199 | ; access, and Omeka will generate URLs that are only valid for a limited 200 | ; time. If the expiration option is missing or left commented out, 201 | ; uploaded files will always be publicly readable. 202 | ; 203 | ; storage.adapter = "Omeka_Storage_Adapter_ZendS3" 204 | ; storage.adapterOptions.accessKeyId = 205 | ; storage.adapterOptions.secretAccessKey = 206 | ; storage.adapterOptions.bucket = 207 | ; storage.adapterOptions.expiration = 10 ; URL expiration time (in minutes) 208 | ; storage.adapterOptions.endpoint = ; Custom S3 endpoint (optional) 209 | 210 | ;;;;;;;;;;;; 211 | ; Security ; 212 | ;;;;;;;;;;;; 213 | 214 | ; ssl 215 | ; Secure Socket Layer support for Omeka. 216 | ; default: none 217 | ; 218 | ; Ensure that your server is properly configured before enabling this 219 | ; setting. Choose one of the following: 220 | ; 221 | ; "logins" 222 | ; Force SSL for login forms and login form submissions. 223 | ; 224 | ; "sessions" 225 | ; Force SSL for all authenticated users to protect sessions. Includes 226 | ; login forms. 227 | ; 228 | ; "always" 229 | ; Force SSL on across the entire site. 230 | ; 231 | ; ssl = "always" 232 | 233 | ;;;;;;;;;; 234 | ; Upload ; 235 | ;;;;;;;;;; 236 | 237 | ; upload.maxFileSize 238 | ; Set the maximum file upload size. 239 | ; default: 10M 240 | ; 241 | ; Uncomment the following line to set the maximum file upload size. This 242 | ; configuration will not exceed the maximum beyond what is set in the 243 | ; 'post_max_size' or 'upload_max_filesize' core php.ini directives. 244 | ; 245 | ;upload.maxFileSize = "10M" 246 | -------------------------------------------------------------------------------- /seed/omeka/templates/db.ini.j2: -------------------------------------------------------------------------------- 1 | [database] 2 | host = "localhost" 3 | username = "omeka" 4 | password = "omeka" 5 | dbname = "omeka" 6 | prefix = "omeka" 7 | charset = "utf8" 8 | ; port = "" 9 | -------------------------------------------------------------------------------- /seed/omeka/templates/omeka.conf.j2: -------------------------------------------------------------------------------- 1 | Listen 8080 2 | NameVirtualHost *:8080 3 | 4 | # The ServerName directive sets the request scheme, hostname and port that 5 | # the server uses to identify itself. This is used when creating 6 | # redirection URLs. In the context of virtual hosts, the ServerName 7 | # specifies what hostname must appear in the request's Host: header to 8 | # match this virtual host. For the default virtual host (this file) this 9 | # value is not decisive as it is used as a last resort host regardless. 10 | # However, you must set it for any further virtual host explicitly. 11 | #ServerName www.example.com 12 | 13 | ServerAdmin webmaster@localhost 14 | DocumentRoot {{ omekadir }} 15 | 16 | Options FollowSymLinks 17 | AllowOverride All 18 | 19 | 20 | Options Indexes FollowSymLinks MultiViews 21 | AllowOverride All 22 | Order allow,deny 23 | Allow from all 24 | 25 | 26 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 27 | # error, crit, alert, emerg. 28 | # It is also possible to configure the loglevel for particular 29 | # modules, e.g. 30 | #LogLevel info ssl:warn 31 | 32 | ErrorLog ${APACHE_LOG_DIR}/error.log 33 | CustomLog ${APACHE_LOG_DIR}/access.log combined 34 | 35 | # For most configuration files from conf-available/, which are 36 | # enabled or disabled at a global level, it is possible to 37 | # include a line for only one particular virtual host. For example the 38 | # following line enables the CGI configuration for this host only 39 | # after it has been globally disabled with "a2disconf". 40 | #Include conf-available/serve-cgi-bin.conf 41 | 42 | -------------------------------------------------------------------------------- /seed/runit_scripts/apache2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## 4 | # Runit run script for apache2 5 | # 6 | 7 | # # Activate the Ubuntu Apache environment 8 | # . /etc/apache2/envvars 9 | # # source /etc/apache2/envvars 10 | # apache2 -V 11 | 12 | # exec /usr/sbin/apache2 -k start -DNO_DETACH 13 | [ ! -d ${APACHE_RUN_DIR:-/var/run/apache2} ] && mkdir -p ${APACHE_RUN_DIR:-/var/run/apache2} 14 | [ ! -d ${APACHE_LOCK_DIR:-/var/lock/apache2} ] && mkdir -p ${APACHE_LOCK_DIR:-/var/lock/apache2} && chown ${APACHE_RUN_USER:-www-data} ${APACHE_LOCK_DIR:-/var/lock/apache2} 15 | exec /usr/sbin/apache2 -e debug >> /var/log/apache.log 2>&1 -------------------------------------------------------------------------------- /seed/runit_scripts/brackets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec brackets --port 4444 --proj-dir /home/ 2>&1 4 | # exec node /brackets-server/bin/run --port 4444 --proj-dir /home/ 2>&1 5 | -------------------------------------------------------------------------------- /seed/runit_scripts/explorer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "starting file explorer" 3 | exec node-file-manager -p 8081 -d /home 2>&1 4 | -------------------------------------------------------------------------------- /seed/runit_scripts/mysql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | echo "starting mysql" 3 | exec 2>&1 4 | exec mysqld_safe --console --user=mysql -------------------------------------------------------------------------------- /seed/runit_scripts/notebook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### In notebook.sh (make sure this file is chmod +x): 3 | # `/sbin/setuser xxxx` runs the given command as the user `xxxx`. 4 | # If you omit that part, the command will be run as root. 5 | echo "Starting Jupyter Notebook" 6 | cd /home 7 | export HASH=$(python3 -c "from IPython.lib import passwd; print(passwd('${PASS}'))") 8 | exec jupyter notebook --no-browser --port 8888 --ip='*' --NotebookApp.password="$HASH" --NotebookApp.tornado_settings='{"headers": {"X-Frame-Options": "ALLOWALL", "Content-Security-Policy": "frame-ancestors *"}}' 9 | -------------------------------------------------------------------------------- /seed/runit_scripts/rserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### In rserver.sh (make sure this file is chmod +x): 3 | # `/sbin/setuser xxxx` runs the given command as the user `xxxx`. 4 | # If you omit that part, the command will be run as root. 5 | 6 | sleep 5 7 | echo "Starting R-Studio" 8 | rstudio-server start >>/var/log/rserver.log 2>&1 9 | 10 | exec /usr/lib/rstudio-server/bin/rserver --server-daemonize=0 >>/var/log/rserver.log 2>&1 -------------------------------------------------------------------------------- /seed/runit_scripts/smtpd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Starting Opensmtp" 3 | exec smtpd -d -------------------------------------------------------------------------------- /seed/runit_scripts/startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | if [ -f /etc/configured ]; then 5 | echo 'already configured' 6 | else 7 | #code to run only one time... 8 | adduser --disabled-password --gecos "" $THEUSER 9 | usermod -a -G sudo $THEUSER 10 | echo "$THEUSER:$PASS" | chpasswd 11 | date > /etc/configured 12 | fi -------------------------------------------------------------------------------- /seed/runit_scripts/wetty.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ### In rserver.sh (make sure this file is chmod +x): 3 | # `/sbin/setuser xxxx` runs the given command as the user `xxxx`. 4 | # If you omit that part, the command will be run as root. 5 | sleep 5 6 | echo "Starting Wetty" 7 | exec wetty -p 4200 2>&1 -------------------------------------------------------------------------------- /src/static/css/main.less: -------------------------------------------------------------------------------- 1 | @import "../bower_components/bootstrap/less/bootstrap.less"; 2 | @import "../bower_components/bootstrap-dialog/src/less/bootstrap-dialog.less"; 3 | @import "../bower_components/fontawesome/less/font-awesome.less"; 4 | @import url(http://fonts.googleapis.com/css?family=Roboto:400,300,400italic,500,500italic,700,700italic); 5 | @import url(http://fonts.googleapis.com/css?family=Inconsolata:400,700); 6 | 7 | 8 | // variables 9 | 10 | @font-family-monospace: "Inconsolata", Consolas, monospace; 11 | @font-family-base: @font-family-monospace; 12 | @font-family-sans-serif: "Roboto", Helvetica, sans-serif; 13 | @brand-primary: #2e1a57; 14 | @btn-default-bg: #fff; 15 | @btn-default-border: @brand-primary; 16 | @btn-default-color: @brand-primary; 17 | @navbar-inverse-bg: @brand-primary; 18 | @navbar-inverse-link-color: #fff; 19 | @container-lg: @container-desktop; 20 | @hr-border: @brand-primary; 21 | @link-color: #428bca; 22 | 23 | // modal styles 24 | 25 | .modal-header-primary { 26 | color:#fff; 27 | padding:9px 15px; 28 | border-bottom:1px solid #eee; 29 | background-color: #428bca; 30 | -webkit-border-top-left-radius: 5px; 31 | -webkit-border-top-right-radius: 5px; 32 | -moz-border-radius-topleft: 5px; 33 | -moz-border-radius-topright: 5px; 34 | border-top-left-radius: 5px; 35 | border-top-right-radius: 5px; 36 | } 37 | 38 | .modal-header-danger { 39 | color:#fff; 40 | padding:9px 15px; 41 | border-bottom:1px solid #eee; 42 | background-color: #d9534f; 43 | -webkit-border-top-left-radius: 5px; 44 | -webkit-border-top-right-radius: 5px; 45 | -moz-border-radius-topleft: 5px; 46 | -moz-border-radius-topright: 5px; 47 | border-top-left-radius: 5px; 48 | border-top-right-radius: 5px; 49 | } 50 | 51 | .modal-dialog { 52 | z-index: 9999; 53 | } 54 | 55 | // shared styles 56 | 57 | .navbar-nav > li > a { 58 | padding: 20px 15px 5px 15px !important; 59 | font-weight: 700; 60 | } 61 | 62 | h1, h2, h3, h4 { 63 | font-family: @font-family-sans-serif; 64 | } 65 | 66 | h1 { 67 | margin-top: 10px; 68 | margin-bottom: 20px; 69 | } 70 | h2, h1.h1-top { 71 | font-weight: 300; 72 | margin-bottom: 5px; 73 | &:first-of-type { 74 | margin-top: 40px; 75 | } 76 | } 77 | 78 | .btn { 79 | border-radius: 0 !important; 80 | border: 1px solid @brand-primary; 81 | color: @brand-primary; 82 | font-weight: 700; 83 | background-color: #fff; 84 | &:hover { 85 | background-color: fade(@brand-primary, 10%); 86 | } 87 | &.btn-huge { 88 | width: 80%; 89 | padding: 30px 0; 90 | } 91 | span:hover { 92 | color:#0f081c; 93 | text-decoration: underline; 94 | } 95 | } 96 | 97 | .form-group { 98 | .form-control { 99 | border-radius: 0 !important; 100 | border: 1px solid @brand-primary; 101 | &.error { 102 | border-color: @brand-danger; 103 | } 104 | &:focus { 105 | border-width: 0 0 1px 0; 106 | box-shadow: none; 107 | padding-left: 13px; 108 | } 109 | &.valid + .help-block { 110 | .fa-exclamation-circle { 111 | display: none; 112 | } 113 | i { 114 | color: @brand-success; 115 | margin-right: 10px; 116 | } 117 | } 118 | &.error + .help-block { 119 | .fa-check { 120 | display: none; 121 | } 122 | i { 123 | color: @brand-danger; 124 | margin-right: 10px; 125 | } 126 | } 127 | } 128 | } 129 | 130 | // layout styles 131 | 132 | .navbar-inverse a.dhbox-logo { 133 | font-size: 28px; 134 | color: #777; 135 | font-weight: 700; 136 | text-decoration: none; 137 | &:hover { 138 | color: #888; 139 | } 140 | span { 141 | color: #fff; 142 | } 143 | } 144 | 145 | .footer { 146 | height: 50px; 147 | } 148 | 149 | 150 | // page styles 151 | .dhbox-home { 152 | .dhbox-welcome { 153 | p.lead { 154 | font-size: 18px; 155 | max-width: @screen-sm; 156 | font-weight: 300; 157 | margin: 20px auto; 158 | } 159 | } 160 | 161 | .dhbox-get { 162 | font-family: @font-family-sans-serif; 163 | 164 | label { 165 | font-size: 24px; 166 | font-weight: 300; 167 | } 168 | > div { 169 | margin-bottom: 30px; 170 | } 171 | } 172 | .dhbox-tools, .dhbox-partners { 173 | font-size: 18px; 174 | p { 175 | margin-bottom: 0; 176 | } 177 | .logos { 178 | margin-top: 20px; 179 | img { 180 | height: 50px; 181 | } 182 | } 183 | } 184 | .dhbox-partners { 185 | .logos > div { 186 | width: 20%; 187 | img { 188 | height: 75px; 189 | } 190 | span { 191 | 192 | } 193 | } 194 | } 195 | } 196 | 197 | 198 | .dhbox-about { 199 | h2:first-of-type { 200 | margin-top: 0; 201 | } 202 | } 203 | 204 | .dhbox-team { 205 | h2 { 206 | font-size: 18px; 207 | font-family: @font-family-monospace; 208 | font-weight: 700; 209 | span { 210 | font-weight: 400; 211 | } 212 | } 213 | } 214 | 215 | .dhbox-signup { 216 | .signup-form { 217 | margin-top: 20px; 218 | } 219 | .btn { 220 | margin-left: 15px; 221 | } 222 | } 223 | 224 | .dhbox-about { 225 | h2:first-of-type { 226 | margin-top: 0; 227 | } 228 | } 229 | 230 | .dhbox-login { 231 | 232 | } 233 | 234 | .dhbox-apps { 235 | margin-top: 25px; 236 | .heading { 237 | font-size: 24px; 238 | } 239 | } 240 | 241 | .fixed_scroll { 242 | overflow-y: hidden; 243 | } -------------------------------------------------------------------------------- /src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/favicon.ico -------------------------------------------------------------------------------- /src/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /src/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /src/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /src/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /src/static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/static/images/britishlibrary-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/britishlibrary-logo.gif -------------------------------------------------------------------------------- /src/static/images/cuny-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/cuny-logo.jpg -------------------------------------------------------------------------------- /src/static/images/dhbox_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/dhbox_shell.png -------------------------------------------------------------------------------- /src/static/images/dhsi-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/dhsi-logo.jpg -------------------------------------------------------------------------------- /src/static/images/hilt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/hilt-logo.png -------------------------------------------------------------------------------- /src/static/images/ipython-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/ipython-logo.png -------------------------------------------------------------------------------- /src/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/logo.png -------------------------------------------------------------------------------- /src/static/images/nypl-logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/nypl-logo.jpg -------------------------------------------------------------------------------- /src/static/images/omeka-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/omeka-logo.gif -------------------------------------------------------------------------------- /src/static/images/rstudio-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DH-Box/dhbox/5a4032ebe190ece13f2de23f950217a7a8df5569/src/static/images/rstudio-logo.png -------------------------------------------------------------------------------- /src/static/js/main.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() { 2 | 3 | $('#appTabs').on('click', function(e) { 4 | paneID = $(e.target).attr('href'); 5 | src = $(paneID).attr('data-src'); 6 | windowHeight = $(window).height() - 100; 7 | $(paneID+" iframe").attr("height",windowHeight); 8 | // if the iframe hasn't already been loaded once 9 | if($(paneID+" iframe").attr("src")=="") 10 | { 11 | $(paneID+" iframe").attr("src",src); 12 | } 13 | }); 14 | 15 | $( "#start-demo" ).click(function(e) { 16 | showModal('Building your Demo DHbox'); 17 | }); 18 | 19 | $( window ).resize(function() { 20 | $('.app-iframe').each(function() { 21 | $(this).attr("height",$( window ).height() - 100); 22 | }); 23 | }); 24 | 25 | var errorTemplate = '
'; 26 | 27 | $.validator.setDefaults({ 28 | debug: false, 29 | success: "has-success" 30 | }); 31 | var form = $( "form" ); 32 | form.validate({ 33 | success: function(label, element) { 34 | label.text("Looks good!"); 35 | }, 36 | errorPlacement: function (error, element) { 37 | var errorElement = $(errorTemplate); 38 | error.appendTo(errorElement); 39 | errorElement.insertAfter(element); 40 | } 41 | }); 42 | $( "#dhbox_form_submit" ).click(function(e) { 43 | e.preventDefault(); 44 | if (form.valid()){ 45 | var x; 46 | var r=true 47 | if (r==true) 48 | { 49 | var allUsers = { users: [] }; 50 | $('.userwrapper').each(function () { 51 | allUsers.users.push({ 52 | name: $(this).find('[what=users]').val(), 53 | pass: $(this).find('[what=passes]').val(), 54 | email: $(this).find('[what=email]').val(), 55 | duration: $(this).find('[what=duration]:checked').val() 56 | }) 57 | }); 58 | showModal('Building your DHbox'); 59 | allUsers.users = allUsers.users.filter(function(n){ return n != undefined }); 60 | mainUser = allUsers.users[0].name 61 | allUsers = JSON.stringify(allUsers); 62 | // console.log(allUsers); 63 | // console.log(mainUser); 64 | $.post('/new_dhbox', allUsers, function(data){ 65 | if (data == 'failure'){ 66 | $('#modal-content').modal('hide'); 67 | $('#failure-modal').modal({show: true}); 68 | }else 69 | { 70 | setTimeout(function () { 71 | alert(data) 72 | window.location = '/dhbox/'+mainUser; 73 | }, 9000); 74 | } 75 | }); 76 | } 77 | else 78 | { 79 | x="!"; 80 | console.log('didnt go through with it'); 81 | } 82 | } 83 | }); 84 | 85 | function showModal(title) { 86 | var modal = $('#progress-modal'); 87 | 88 | modal.find('.modal-title').text(title); 89 | 90 | modal.modal('show'); 91 | } 92 | 93 | $.validator.addMethod( 94 | "regex", 95 | function(value, element, regexp) { 96 | var re = new RegExp(regexp); 97 | return this.optional(element) || re.test(value); 98 | }, 99 | "Please check your input. No capital letters or spaces." 100 | ); 101 | $("#admin").rules("add", { regex: "^[a-z][-a-z0-9]*\$" }) 102 | // $("#admin").rules("add", { regex: "^[a-z][-a-z0-9]*\$" }) 103 | 104 | }); -------------------------------------------------------------------------------- /src/templates/.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | # Virtualenv 38 | .Python 39 | bin 40 | lib 41 | include 42 | 43 | # Mac OS X custom attribute files 44 | .DS_Store -------------------------------------------------------------------------------- /src/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |

About

5 | 6 |
7 | 8 |

What is it?

9 | 10 | 11 |

DH Box is a laboratory in the cloud that can be deployed quickly and easily. It's simply accessed from any computer 12 | as long as you've got an internet connection and some contextual knowledge.

13 | 14 |
15 | 16 |

Ready-to-go configurations of Omeka, NLTK, IPython, R Studio, and Mallet are included in the DH Box 21 | platform. Through this praxis friendly environment, professors and students have instant classroom access to a cadre 22 | of gold-standard DH tools. Professors will be able to launch a DH computer lab in just a few minutes.

23 | 24 |
25 | 26 |

Why use it?

27 | 28 |

With DH Box, faculty have the freedom to integrate DH tools into their curriculum without relying on external server 29 | administration or having to deal with labor intensive software installations, firewalls, and operating system 30 | configurations.

31 | 32 |
33 | 34 |

DH Box is device agnostic so scholars can research wherever there's an internet connection.

35 | 36 |
37 | 38 |

Who is it ideal for?

39 | 40 |

DH Box is being developed for college faculty who have familiarity with DH tools like Omeka, NLTK, R Studio, and 41 | Mallet. Do you know what the command line is? Do you know what a server does?

42 | 43 |
44 | 45 |

If you're unfamiliar with any of the above, we recommend you engage with some other resources first. Here are several 46 | places we recommend exploring:

47 | 48 |
49 | 50 |

The Command Line the Hard Way by 51 | Zed Shaw

52 | 53 |

Computer 54 | processing terminology by the Apache Software Foundation

55 | 56 |

Programming Lessons by the 57 | Programming Historian

58 | 59 |

How did they make 60 | that? deconstructing DH projects by Miriam Posner

61 | 62 |
63 | 64 |
65 |
66 | 67 |

68 | 69 | 70 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/admin.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Administration

4 |
5 | 6 | 7 | 8 | 9 | 10 | {% if containers %} 11 | {%for container in containers%} 12 | 13 | 14 | 15 | 16 | 22 | 23 | {%endfor%} 24 | {%else%} 25 | No containers 26 | {% endif %} 27 |
OwnerTime UpTime LeftButton
{{container.name}}{{container.uptime}}{{container.time_left}} 17 |
18 | 19 | 20 | 21 |
28 |

Container Info

29 |
30 |
31 | {% if containers %}
32 |     {{containers}}
33 | {% endif %}
34 | 
35 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/contact.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Contact

4 | 5 |
6 | 7 |

We've begun building a community of educators, librarians, and developers organized around increasing the utility of 8 | DH Box and DH tools in academia. We plan to add more tools and make improvements based on community input.

9 | 10 |

Questions or comments? We'd love to hear from you!

11 | 12 |

Email hello [at] dhbox [dot] 13 | org or find us on Twitter.

14 | 15 | 16 | 17 |

18 | 19 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/dhbox.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |
5 |
6 | 15 | 16 |
17 |
18 |
19 | {%if demo%} 20 |
21 |

22 | This is a DEMONSTRATION DH Box 23 | 24 |

25 |
26 |

User/pass for all applications:

27 |

demonstration/demonstration

28 |
29 | {%endif%} 30 |
31 |
32 | 34 |

This is your DH Box's homepage.

35 |

User/pass for all applications is the same as for DH Box.

36 |

Your DH Box will expire in: {{time_left}}.

37 |

38 |
39 |
40 |
41 | {% for app in apps %} 42 | {% if app['port'] %} 43 |
44 | 45 |
46 | {% endif %} 47 | {% endfor %} 48 | {% if port_4000 %} 49 |
50 | 51 |
52 | {% else %} 53 |
54 | 55 |
56 | {% endif %} 57 |
58 |
59 |
60 |
61 | 62 | {% endblock %} 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/templates/get_started.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |

Get Started

4 | 5 |
6 | 7 |

DH Box is currently under development. Check our GitHub 8 | to see what's new.

9 | 10 |
11 | 12 | 13 | 14 | 15 |

16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |
5 |
6 |

7 | 9 |

{{institution}}

10 | 11 |

Setting up an environment for digital humanities computational work can be time-consuming 12 | and difficult. DH Box addresses this problem by streamlining installation processes and providing a 13 | digital humanities laboratory in the cloud through simple sign-in via a web browser.

14 |
15 | 16 |
17 | {% if demo %} 18 |
19 |
20 |
21 | Start Hour-Long Demo 22 |
23 |
24 |
25 | Sign Up 26 |
27 |
28 |
29 | Download from GitHub 30 |
31 |
32 | {% else %} 33 |
34 |
35 |
36 | Sign Up 37 |
38 |
39 |
40 | Download from GitHub 41 |
42 |
43 | {% endif %} 44 |
45 |
46 |
47 |

The DH Box platform comes pre-equipped with essential DH tools:

48 | 49 |

IPython, RStudio, Omeka, and NLTK.

50 |
51 |
52 |
53 |
54 | omeka 55 |
56 |
57 | ipython 58 |
59 |
60 | rstudio 61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |

DH Box is created in partnership with:

69 |
70 |
71 |
72 |
73 | British Library 74 |
75 |
76 | CUNY 77 |
78 |
79 | NYPL 80 |
81 |
82 | HILT 83 |
84 |
85 | dhsi.org 86 |
87 |
88 |
89 |
90 | {% endblock %} 91 | -------------------------------------------------------------------------------- /src/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DH Box 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 76 |
77 |
78 | 79 | {% with messages = get_flashed_messages() %} 80 | {% if messages %} 81 |
82 | {% for message in messages %} 83 |
84 |
85 | 86 | {{message}} {{message.category}} 87 |
88 |
89 | {% endfor %} 90 |
91 | {% endif %} 92 | {% endwith %} 93 | 94 | {% block body %}{% endblock %} 95 |
96 | 98 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/templates/news.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% filter markdown %} 4 | {% for news in news_list %} 5 |   6 | 7 |   8 | 9 | {{news}} 10 | {% endfor %} 11 | {% endfilter %} 12 | {% endblock %} 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/templates/our_team.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 |
4 |

Our Team

5 |
6 |
7 |

Stephen Zweibel 8 | Lead Developer 9 |

10 |
11 |
12 |
13 |
14 |

Patrick Smyth 15 | Developer, Writer 16 |

17 |
18 |
19 |
20 |
21 |

Jojo Karlin 22 | Outreach Coordinator 23 |

24 |
25 |
26 |
27 |
28 |

Matthew K. Gold 29 | Academic Advisor 30 |

31 |
32 |
33 |
34 |
35 |
36 |

Other Contributors

37 |
38 |
39 |

Dennis Tenen 40 | Academic Advisor 41 |

42 |
43 |
44 |
45 |
46 |

Harlan Kellaway 47 | Project Alumni 48 |

49 |
50 |
51 |
52 |
53 |

Gioia Stevens 54 | Project Alumni 55 |

56 |
57 |
58 | 59 |
60 |
61 |

Evan Misshula 62 | Project Alumni 63 |

64 |
65 |
66 |
67 |
68 |

Micki Kaufman 69 | Project Alumni 70 |

71 |
72 |
73 |
74 |
75 |

Cailean Cooney 76 | Project Alumni 77 |

78 |
79 |
80 |
81 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/port.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DH Box 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 | 33 |

This tab will display anything on port 4000.

34 |
    35 |
  • Host: 0.0.0.0
  • 36 |
  • Port: 4000
  • 37 |
38 |

39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/templates/security/login_user.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | {% from "security/_macros.html" import render_field_with_errors, render_field %} 4 | {% include "security/_messages.html" %} 5 | 37 | 38 | {% endblock %} -------------------------------------------------------------------------------- /src/templates/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 67 | {% endblock %} 68 | -------------------------------------------------------------------------------- /src/templates/test.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 73 | 74 |
75 | 76 |

Launch a New DH Box

77 | 78 |
79 | 80 |

You're about to become the owner of a brand new DH Box.

81 | 82 |
83 | 84 | Just fill out the information below then click Launch. 85 | 86 |

87 | 88 |
89 | 90 |
91 | 92 |
93 |
94 |
95 |
96 | 97 | 99 | This is the user with complete control over a new DH Box. 100 |
101 |
102 | 103 | 105 | Passwords apply for access to: DH Box, Omeka, RStudio. 106 |
107 |
108 | 109 | 111 |
112 |
113 |
114 |
115 | 116 | Should anyone else - such as students - be able to access this DH Box? 117 | 118 |
119 | 120 | 123 |
124 |
125 | 126 |
127 | 128 |
129 |
130 | 131 |
132 | {% endblock %} -------------------------------------------------------------------------------- /static/css/bootstrap-dialog.min.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog .modal-header{border-top-left-radius:4px;border-top-right-radius:4px}.bootstrap-dialog .bootstrap-dialog-title{color:#fff;display:inline-block}.bootstrap-dialog.type-default .bootstrap-dialog-title{color:#333}.bootstrap-dialog .bootstrap-dialog-title{font-size:16px}.bootstrap-dialog.size-large .bootstrap-dialog-title{font-size:24px}.bootstrap-dialog .bootstrap-dialog-close-button{float:right;filter:alpha(opacity=90);-moz-opacity:.9;-khtml-opacity:.9;opacity:.9}.bootstrap-dialog .bootstrap-dialog-close-button{font-size:20px}.bootstrap-dialog.size-large .bootstrap-dialog-close-button{font-size:30px}.bootstrap-dialog .bootstrap-dialog-close-button:hover{cursor:pointer;filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}.bootstrap-dialog .bootstrap-dialog-message{font-size:14px}.bootstrap-dialog.size-large .bootstrap-dialog-message{font-size:18px}.bootstrap-dialog.type-default .modal-header{background-color:#fff}.bootstrap-dialog.type-info .modal-header{background-color:#5bc0de}.bootstrap-dialog.type-primary .modal-header{background-color:#428bca}.bootstrap-dialog.type-success .modal-header{background-color:#5cb85c}.bootstrap-dialog.type-warning .modal-header{background-color:#f0ad4e}.bootstrap-dialog.type-danger .modal-header{background-color:#d9534f}.bootstrap-dialog .bootstrap-dialog-button-icon{margin-right:3px}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0{-ms-transform:rotate(0)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0{transform:rotate(0)}100%{transform:rotate(359deg)}} -------------------------------------------------------------------------------- /static/css/custom.css: -------------------------------------------------------------------------------- 1 | /*****************************************************************************/ 2 | /* 3 | /* Custom 4 | /* 5 | /*****************************************************************************/ 6 | 7 | html { 8 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | font-weight: 400; 10 | font-size: 15px; 11 | } 12 | 13 | p { 14 | margin-left: 0px; 15 | margin-right: 150px; 16 | } 17 | 18 | body { 19 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 20 | font-size: 125%; 21 | } 22 | 23 | .dhbox { 24 | font-family: "Helvetica", "Helvetica Neue", Helvetica, Arial, sans-serif; 25 | } 26 | 27 | hr { 28 | border: 0; 29 | border-bottom: 3px dashed #333; 30 | background: #999; 31 | margin-right: 50px; 32 | } 33 | 34 | .logo-custom { 35 | height: 60px; 36 | width: auto; 37 | border: 2px solid white; 38 | } 39 | 40 | .advisor > h2 { 41 | font-size: 20px; 42 | } 43 | 44 | div:target { 45 | padding-top: 60px; 46 | } 47 | 48 | .missingpage { 49 | margin-left: 50px; 50 | } 51 | 52 | .headline > .container > h3 { 53 | background: #ffffff; 54 | background: rgba(255, 255, 255, 0.9); 55 | color: #3C0987; 56 | } 57 | 58 | .404 { 59 | margin-left: 50px; 60 | } 61 | 62 | .why { 63 | font-weight: bold; 64 | } 65 | 66 | .blog { 67 | margin-left: 50px; 68 | margin-right: 50px; 69 | } 70 | 71 | .breadcrumbtrail { 72 | text-align: center; 73 | margin-right: 50px; 74 | } 75 | 76 | .post { 77 | margin-left: 80px; 78 | margin-right: 80px; 79 | } 80 | 81 | .postheader { 82 | margin-bottom: 20px; 83 | } 84 | 85 | .post .date { 86 | font-style: italic; 87 | } 88 | 89 | .postprint { 90 | margin-left: 10px; 91 | margin-right: 10px; 92 | } 93 | 94 | .posts { 95 | list-style-type: none; 96 | margin-bottom: 2em; 97 | } 98 | 99 | .posts li { 100 | line-height: 1.75em; 101 | } 102 | 103 | .posts span { 104 | color: #666; 105 | font-family: Monaco, "Courier New", monospace; 106 | font-size: 80%; 107 | } 108 | 109 | .footer { 110 | color: #333; 111 | margin-left: 50px; 112 | } 113 | 114 | .footer a, a.hover, a.visited { 115 | color: #333; 116 | text-decoration: underline; 117 | } 118 | 119 | .footer .socialmedia { 120 | float: right; 121 | overflow: hidden; 122 | text-decoration: none; 123 | margin-right:50px; 124 | } 125 | 126 | .footer .socialmedia a { 127 | text-decoration: none; 128 | } 129 | 130 | .backtotop a, a.hover, a.visited { 131 | text-decoration: none; 132 | } 133 | 134 | .footer .socialmedia { 135 | text-align: right; 136 | } 137 | 138 | .footer > .menu { 139 | text-align: left; 140 | } 141 | 142 | .credits { 143 | font-size: 65%; 144 | } 145 | 146 | .searchdescription { 147 | color: #333; 148 | font-size: 75%; 149 | margin-left: 10px; 150 | } 151 | 152 | .myicon { 153 | width: 32px; 154 | height: 32px; 155 | } 156 | 157 | /* .face { 158 | width: 200px; 159 | height: auto; 160 | } */ -------------------------------------------------------------------------------- /static/css/modals.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | .modal-header-primary { 4 | color: #fff; 5 | padding: 9px 15px; 6 | border-bottom: 1px solid #eee; 7 | background-color: #428bca; 8 | -webkit-border-top-left-radius: 5px; 9 | -webkit-border-top-right-radius: 5px; 10 | -moz-border-radius-topleft: 5px; 11 | -moz-border-radius-topright: 5px; 12 | border-top-left-radius: 5px; 13 | border-top-right-radius: 5px; 14 | } 15 | 16 | .modal-header-danger { 17 | color: #fff; 18 | padding: 9px 15px; 19 | border-bottom: 1px solid #eee; 20 | background-color: #d9534f; 21 | -webkit-border-top-left-radius: 5px; 22 | -webkit-border-top-right-radius: 5px; 23 | -moz-border-radius-topleft: 5px; 24 | -moz-border-radius-topright: 5px; 25 | border-top-left-radius: 5px; 26 | border-top-right-radius: 5px; 27 | } -------------------------------------------------------------------------------- /static/css/my_dhbox.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | body { 4 | font-family: "Century Gothic", CenturyGothic, AppleGothic, sans-serif; 5 | font-size: 20px; 6 | } 7 | 8 | .full { 9 | background-image: url('http://dhbox.org/images/background.png') repeat; 10 | background-color: #FFFFFF; 11 | background-position: top; 12 | height: auto; 13 | display: block; 14 | width: 100%; 15 | } 16 | 17 | .jumbotron {text-align: center;} 18 | 19 | .btn-custom { 20 | padding: 14px 22px; 21 | font-size: 17px; 22 | line-height: normal; 23 | -webkit-border-radius: 6px; 24 | -moz-border-radius: 6px; 25 | border-radius: 6px; 26 | } 27 | 28 | .headline > .description {font-size: 30px;} 29 | 30 | .welcomepage > .container > .heading { 31 | font-size: 40px; 32 | color: #3C0987; 33 | } 34 | 35 | .welcomepage > .container > hr { 36 | border: 0; 37 | border-bottom: 3px dashed #333; 38 | background: #999; 39 | } 40 | 41 | .highlight { 42 | background: rgba(255, 230, 0, 0.5); 43 | padding: 3px 5px; 44 | margin: -3px -5px; 45 | line-height: 1.7; 46 | border-radius: 3px; 47 | display: inline-block; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /wp-seed/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM thedhbox/tlamp 2 | MAINTAINER Fernando Mayo , Feng Honglin 3 | 4 | # Install plugins 5 | RUN apt-get update && \ 6 | apt-get -y install php5-gd && \ 7 | rm -rf /var/lib/apt/lists/* 8 | 9 | # Download latest version of Wordpress into /app 10 | RUN rm -fr /app && git clone --depth=1 https://github.com/WordPress/WordPress.git /app 11 | 12 | # Configure Wordpress to connect to local DB 13 | ADD wp-config.php /app/wp-config.php 14 | 15 | # Modify permissions to allow plugin upload 16 | RUN chown -R www-data:www-data /app/wp-content /var/www/html 17 | 18 | # Add database setup script 19 | ADD create_mysql_admin_user.sh /create_mysql_admin_user.sh 20 | ADD create_db.sh /create_db.sh 21 | RUN chmod +x /*.sh 22 | 23 | EXPOSE 80 3306 24 | CMD ["/run.sh"] 25 | 26 | VOLUME /app 27 | -------------------------------------------------------------------------------- /wp-seed/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /wp-seed/README.md: -------------------------------------------------------------------------------- 1 | tutum-docker-wordpress 2 | ====================== 3 | 4 | [![Deploy to Tutum](https://s.tutum.co/deploy-to-tutum.svg)](https://dashboard.tutum.co/stack/deploy/) 5 | 6 | Out-of-the-box Wordpress docker image 7 | 8 | 9 | Usage 10 | ----- 11 | 12 | To create the image `tutum/wordpress`, execute the following command on the tutum-docker-wordpress folder: 13 | 14 | docker build -t tutum/wordpress . 15 | 16 | You can now push your new image to the registry: 17 | 18 | docker push tutum/wordpress 19 | 20 | 21 | Running your Wordpress docker image 22 | ----------------------------------- 23 | 24 | Start your image: 25 | 26 | docker run -d -p 80:80 tutum/wordpress 27 | 28 | Test your deployment: 29 | 30 | curl http://localhost/ 31 | 32 | You can now start configuring your Wordpress container! 33 | 34 | 35 | More information 36 | ---------------- 37 | 38 | For details on how to access the bundled MySQL Server, set specific passwords or disable .htaccess, 39 | please visit the [tutum/lamp repository on github](https://github.com/tutumcloud/tutum-docker-lamp) 40 | -------------------------------------------------------------------------------- /wp-seed/create_db.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [[ $# -eq 0 ]]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | /usr/bin/mysqld_safe > /dev/null 2>&1 & 9 | 10 | echo "=> Creating database $1" 11 | RET=1 12 | while [[ RET -ne 0 ]]; do 13 | sleep 5 14 | mysql -uroot -e "CREATE DATABASE $1" 15 | RET=$? 16 | done 17 | 18 | mysqladmin -uroot shutdown 19 | 20 | echo "=> Done!" 21 | -------------------------------------------------------------------------------- /wp-seed/create_mysql_admin_user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /usr/bin/mysqld_safe > /dev/null 2>&1 & 4 | 5 | RET=1 6 | while [[ RET -ne 0 ]]; do 7 | echo "=> Waiting for confirmation of MySQL service startup" 8 | sleep 5 9 | mysql -uroot -e "status" > /dev/null 2>&1 10 | RET=$? 11 | done 12 | 13 | echo "=> Creating database wordpress in MySQL" 14 | /create_db.sh wordpress 15 | 16 | 17 | PASS=${MYSQL_PASS:-$(pwgen -s 12 1)} 18 | _word=$( [ ${MYSQL_PASS} ] && echo "preset" || echo "random" ) 19 | echo "=> Creating MySQL admin user with ${_word} password" 20 | 21 | mysql -uroot -e "CREATE USER 'admin'@'%' IDENTIFIED BY '$PASS'" 22 | mysql -uroot -e "GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION" 23 | 24 | 25 | echo "=> Done!" 26 | 27 | echo "========================================================================" 28 | echo "You can now connect to this MySQL Server using:" 29 | echo "" 30 | echo " mysql -uadmin -p$PASS -h -P" 31 | echo "" 32 | echo "Please remember to change the above password as soon as possible!" 33 | echo "MySQL user 'root' has no password but only allows local connections" 34 | echo "========================================================================" 35 | 36 | mysqladmin -uroot shutdown 37 | -------------------------------------------------------------------------------- /wp-seed/tutum.yml: -------------------------------------------------------------------------------- 1 | wordpress: 2 | image: tutum/wordpress 3 | ports: 4 | - 80:80 5 | -------------------------------------------------------------------------------- /wp-seed/wp-config.php: -------------------------------------------------------------------------------- 1 | g:EOH>e-ZXs!7x(: W4:}1A2$E?Sn9P>TW-[=:u[nc-eQzj5C1krtu:>2VT(WlI/Jl5T~Pov2-`r+Zb5s3i6&aIN$*/+k/~sLN'); 48 | define('NONCE_KEY', '~; xvP`h^{Pl9zaD#/!f@M21BAk0#sKg>*P+=1LV+FY+;HNE)%Y`4(Xq|&})fCj^'); 49 | define('AUTH_SALT', 'A2|G[jvSLB+z dy S/ S>(lLyzxDvJ8(ps1(F%~x]eRD`UHv(h*IDjye+SYV-a;O'); 50 | define('SECURE_AUTH_SALT', '9cv/Hy~a;qr]4)i*udy-/$non@_:CU0SIdm-L[WH^k_}s:Jq[)HV,Wu8na<_;ef3'); 51 | define('LOGGED_IN_SALT', '{d*4OCrk9x`|cb-4EBK7=ewJ3D]y%z,7mSEd:8?=eP![zD.O`