From 23357dfd208cc0176602c803b6f98566e3064243 Mon Sep 17 00:00:00 2001 From: Zachary Seguin Date: Sat, 11 Aug 2018 11:30:26 -0400 Subject: [PATCH] Initial commit --- .gitignore | 3 + Makefile | 124 ++++++++++ content/pages/advanced-networking.md | 62 +++++ content/pages/cli-access.md | 19 ++ content/pages/docs.md | 16 ++ content/pages/faq.md | 23 ++ content/pages/getting-started.md | 81 ++++++ content/pages/home.md | 14 ++ content/pages/usage-agreement.md | 88 +++++++ content/pages/user-setup.md | 41 +++ develop_server.sh | 103 ++++++++ fabfile.py | 92 +++++++ pelicanconf.py | 45 ++++ publishconf.py | 24 ++ themes/csclub/static/css/main.css | 101 ++++++++ themes/csclub/static/images/csc_logo.png | Bin 0 -> 14247 bytes themes/csclub/static/images/csc_logo.svg | 94 +++++++ themes/csclub/static/images/uw_logo.png | Bin 0 -> 21100 bytes themes/csclub/static/images/uw_logo.svg | 247 +++++++++++++++++++ themes/csclub/templates/archives.html | 11 + themes/csclub/templates/article.html | 44 ++++ themes/csclub/templates/author.html | 7 + themes/csclub/templates/authors.html | 13 + themes/csclub/templates/base.html | 78 ++++++ themes/csclub/templates/categories.html | 8 + themes/csclub/templates/category.html | 5 + themes/csclub/templates/gosquared.html | 14 ++ themes/csclub/templates/index.html | 28 +++ themes/csclub/templates/page.html | 15 ++ themes/csclub/templates/pagination.html | 11 + themes/csclub/templates/period_archives.html | 11 + themes/csclub/templates/tag.html | 0 themes/csclub/templates/tags.html | 10 + themes/csclub/templates/translations.html | 9 + 34 files changed, 1441 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 content/pages/advanced-networking.md create mode 100644 content/pages/cli-access.md create mode 100644 content/pages/docs.md create mode 100644 content/pages/faq.md create mode 100644 content/pages/getting-started.md create mode 100644 content/pages/home.md create mode 100644 content/pages/usage-agreement.md create mode 100644 content/pages/user-setup.md create mode 100755 develop_server.sh create mode 100644 fabfile.py create mode 100644 pelicanconf.py create mode 100644 publishconf.py create mode 100644 themes/csclub/static/css/main.css create mode 100644 themes/csclub/static/images/csc_logo.png create mode 100644 themes/csclub/static/images/csc_logo.svg create mode 100644 themes/csclub/static/images/uw_logo.png create mode 100644 themes/csclub/static/images/uw_logo.svg create mode 100644 themes/csclub/templates/archives.html create mode 100644 themes/csclub/templates/article.html create mode 100644 themes/csclub/templates/author.html create mode 100644 themes/csclub/templates/authors.html create mode 100644 themes/csclub/templates/base.html create mode 100644 themes/csclub/templates/categories.html create mode 100644 themes/csclub/templates/category.html create mode 100644 themes/csclub/templates/gosquared.html create mode 100644 themes/csclub/templates/index.html create mode 100644 themes/csclub/templates/page.html create mode 100644 themes/csclub/templates/pagination.html create mode 100644 themes/csclub/templates/period_archives.html create mode 100644 themes/csclub/templates/tag.html create mode 100644 themes/csclub/templates/tags.html create mode 100644 themes/csclub/templates/translations.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d9f2e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycacahe__/ +*.pyc +output/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..defc9be --- /dev/null +++ b/Makefile @@ -0,0 +1,124 @@ +PY?=python3 +PELICAN?=pelican +PELICANOPTS= + +BASEDIR=$(CURDIR) +INPUTDIR=$(BASEDIR)/content +OUTPUTDIR=$(BASEDIR)/output +CONFFILE=$(BASEDIR)/pelicanconf.py +PUBLISHCONF=$(BASEDIR)/publishconf.py + +FTP_HOST=localhost +FTP_USER=anonymous +FTP_TARGET_DIR=/ + +SSH_HOST=web1.cloud.csclub.uwaterloo.ca +SSH_PORT=22 +SSH_USER=ztseguin +SSH_TARGET_DIR=/srv/http/cloud.csclub.uwaterloo.ca + +S3_BUCKET=my_s3_bucket + +CLOUDFILES_USERNAME=my_rackspace_username +CLOUDFILES_API_KEY=my_rackspace_api_key +CLOUDFILES_CONTAINER=my_cloudfiles_container + +DROPBOX_DIR=~/Dropbox/Public/ + +GITHUB_PAGES_BRANCH=gh-pages + +DEBUG ?= 0 +ifeq ($(DEBUG), 1) + PELICANOPTS += -D +endif + +RELATIVE ?= 0 +ifeq ($(RELATIVE), 1) + PELICANOPTS += --relative-urls +endif + +help: + @echo 'Makefile for a pelican Web site ' + @echo ' ' + @echo 'Usage: ' + @echo ' make html (re)generate the web site ' + @echo ' make clean remove the generated files ' + @echo ' make regenerate regenerate files upon modification ' + @echo ' make publish generate using production settings ' + @echo ' make serve [PORT=8000] serve site at http://localhost:8000' + @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' + @echo ' make devserver [PORT=8000] start/restart develop_server.sh ' + @echo ' make stopserver stop local server ' + @echo ' make ssh_upload upload the web site via SSH ' + @echo ' make rsync_upload upload the web site via rsync+ssh ' + @echo ' make dropbox_upload upload the web site via Dropbox ' + @echo ' make ftp_upload upload the web site via FTP ' + @echo ' make s3_upload upload the web site via S3 ' + @echo ' make cf_upload upload the web site via Cloud Files' + @echo ' make github upload the web site via gh-pages ' + @echo ' ' + @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' + @echo 'Set the RELATIVE variable to 1 to enable relative urls ' + @echo ' ' + +html: + $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) + +clean: + [ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR) + +regenerate: + $(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) + +serve: +ifdef PORT + cd $(OUTPUTDIR) && $(PY) -m pelican.server $(PORT) +else + cd $(OUTPUTDIR) && $(PY) -m pelican.server +endif + +serve-global: +ifdef SERVER + cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 $(SERVER) +else + cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0 +endif + + +devserver: +ifdef PORT + $(BASEDIR)/develop_server.sh restart $(PORT) +else + $(BASEDIR)/develop_server.sh restart +endif + +stopserver: + $(BASEDIR)/develop_server.sh stop + @echo 'Stopped Pelican and SimpleHTTPServer processes running in background.' + +publish: + $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS) + +ssh_upload: publish + scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) + +rsync_upload: publish + rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude + +dropbox_upload: publish + cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR) + +ftp_upload: publish + lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit" + +s3_upload: publish + s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed --guess-mime-type --no-mime-magic --no-preserve + +cf_upload: publish + cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) . + +github: publish + ghp-import -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $(OUTPUTDIR) + git push origin $(GITHUB_PAGES_BRANCH) + +.PHONY: html help clean regenerate serve serve-global devserver stopserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github diff --git a/content/pages/advanced-networking.md b/content/pages/advanced-networking.md new file mode 100644 index 0000000..17946c5 --- /dev/null +++ b/content/pages/advanced-networking.md @@ -0,0 +1,62 @@ +title: Advanced Networking +slug: docs/advanced-networking +status: hidden + +## Static Networking + +Information for the `MSO Intranet` networking: + +Addresses are assigned from these ranges: + +``` +IPv4: 172.19.134.0/24 +IPv6: 2620:101:f000:4903::/64 +``` + +Network gateways: + +``` +IPv4 Gateway: 172.19.134.254 (NAT gateway) + Add routes to campus: + 10.0.0.0/8 via 172.19.134.1 + 129.97.0.0/16 via 172.19.134.1 + 172.16.0.0/12 via 172.19.134.1 + + Please do not send on-campus traffic through the NAT gateway. + This may be blocked in the future. + +IPv6 Gateway: 2620:101:f000:4903::1 +``` + +## Firewall + +### Campus Firewall + +All machines in the CSC cloud are behind the Campus Firewall. The Campus +Firewall blocks all incoming traffic at the University border. + +**We will not accept requests for exceptions to the campus firewall. All +inbound traffic originating from off-campus will be blocked.** + +### OpenStack Security Groups + +You can utilize OpenStack Security Groups to act as a firewall in front of your +host. + +*More documentation about this will come at a later time.* + +## Private Networking + +See [OpenStack Horizon Documentation](https://docs.openstack.org/horizon/pike/user/create-networks.html) for +information about creating private networks. + +### Disabling Port Security + +Disabling port security is required if you are running a router on your network +(ie. traffic with source IPs different than your own). + +*This cannot be done for the MSO Intranet network, however can be done for +private networks*. + +This can only be done via the OpenStack command line and the API: +`openstack port set --disable-port-security --no-security-group [portid]` diff --git a/content/pages/cli-access.md b/content/pages/cli-access.md new file mode 100644 index 0000000..49bd762 --- /dev/null +++ b/content/pages/cli-access.md @@ -0,0 +1,19 @@ +title: Command Line Access +slug: docs/cli-access +status: hidden + +The OpenStack command line interface has been installed on corn-syrup. + +Set the following environment variables to authenticate with the CSC Cloud: + +```bash +export OS_USERNAME= +export OS_PROJECT_NAME= +export OS_USER_DOMAIN_NAME=csclub +export OS_PROJECT_DOMAIN_NAME=csclub +export OS_AUTH_URL=https://auth.cloud.csclub.uwaterloo.ca/v3 +export OS_IDENTITY_API_VERSION=3 +``` + +Documentation on the command line is available from the OpenStack project: +[OpenStackClient](https://docs.openstack.org/python-openstackclient/latest/). diff --git a/content/pages/docs.md b/content/pages/docs.md new file mode 100644 index 0000000..6598c6b --- /dev/null +++ b/content/pages/docs.md @@ -0,0 +1,16 @@ +title: Documentation +slug: docs + +## For users + +- [Getting Started]({filename}getting-started.md) +- [CLI Access]({filename}cli-access.md) +- [Advanced Networking]({filename}advanced-networking.md) + +A great resource is the [OpenStack user +guides](https://docs.openstack.org/ocata/user/) (Note: we are currently running +the Ocata version). + +## For administrators + +- [User Setup]({filename}user-setup.md) diff --git a/content/pages/faq.md b/content/pages/faq.md new file mode 100644 index 0000000..30e51c1 --- /dev/null +++ b/content/pages/faq.md @@ -0,0 +1,23 @@ +title: Frequently Asked Questions +slug: faq +status: hidden + +## Networking + +### What IP ranges are available? + +When you create a server on the `MSO Intranet` network, you are assigned an +IPv4 address in the range of `172.19.134.0/24` and an IPv6 address in the range +of `2620:101:f000:4903::/64`. + +### How can I access my server? + +To access your server you must be connected to the University's network. This +can be done via wired, wireless (Eduroam) or the +[VPN](https://uwaterloo.ca/information-systems-technology/services/virtual-private-network-vpn). + +### I'm assigned a globally-routed IPv6 address. Why can't I access it from the internet? + +All traffic to your server initiated from off-campus is blocked at the +University's border firewall. We are not accepting requests for exceptions at +this time. diff --git a/content/pages/getting-started.md b/content/pages/getting-started.md new file mode 100644 index 0000000..4b42d81 --- /dev/null +++ b/content/pages/getting-started.md @@ -0,0 +1,81 @@ +title: Getting Started +slug: docs/getting-started +status: hidden + +## Prerequisites + +- **Beta**: You must request and be granted access from the cloud@csclub.uwaterloo.ca to use the + Computer Science Club Cloud. *Please include your CSC username when + requesting access*. + +## Accessing the Dashboard + +1. Go to [Computer Science Club Cloud + Dashboard](https://dashboard.cloud.csclub.uwaterloo.ca/) +2. Login with your Computer Science Club username and password + +## Creating a server + +1. On the Dashboard, open `Project` → `Compute` → `Instances`. +2. Click `Launch Instance` +3. Fill in instance details + - Select a name + - Choose `csc-mc` availability zone +4. Click next. Select an image +5. Click next. Choose a flavour +6. Click next. Select a network + - Select `MSO Intranet` (unless you are working with private networking, + see the Advanced Network Guide) +7. Click on `Key Pair` + - If you have not already uploaded a SSH key pair, upload your public key + - *This step is important. Without a SSH key, you will not be able to + access your VM.* +8. Click `Launch Instance` + +> *If* everything works correctly, your VM *should* be provisioned. + +## Accessing the server + +The dashboard will show the IP addresses assigned to the VM. You can SSH +using the corresponding SSH private key. + +The default username is typically the name of the distribution (e.g., `ubuntu` +for Ubuntu and `debian` for Debian). + + +**You cannot connect to your VM from the internet. You must connect by SSH'ing +from a CSC machine or by using on-campus ethernet, wireless or the +[Campus VPN](https://uwaterloo.ca/information-systems-technology/services/virtual-private-network-vpn).** + +You may wish to configure an account password (using `passwd`) to allow access +via the console (see the next section). + +## Oh no! I broke SSH / Networking / etc. + +You can access the console through the dashboard. View the instance details (by +clicking its name) and then click on the `Console` tab. + +The console may not accept keyboard / mouse input. If so, click on `Click here +to show only console` to access the fullscreen view. + +## Mirrors + +If possible, you should use +[mirror.csclub.uwaterloo.ca](http://mirror.csclub.uwaterloo.ca) as your mirror. + +## Web Hosting + +As you may have noticed, you cannot access your VM from the internet. To allow +access to your website, you have two options: + +1. Proxy through `caffeine`. See the [CSC + wiki](https://wiki.csclub.uwaterloo.ca/Web_Hosting#Reverse_Proxy_.28Python.2C_Ruby.2C_Perl.2C_etc..29) + for more information +2. Configure on the CSC HAProxy load balancer. Contact + cloud@csclub.uwaterloo.ca with your domain name, username, instance IP + addresses and ports (or DNS hostname). TLS certificates are currently only + available for `*.csclub.cloud` domains (contact cloud@csclub.uwaterloo.ca to + register a `[yourusername-blah].csclub.cloud` hostname). + + diff --git a/content/pages/home.md b/content/pages/home.md new file mode 100644 index 0000000..49bc237 --- /dev/null +++ b/content/pages/home.md @@ -0,0 +1,14 @@ +Title: CSC Cloud (Beta) +URL: +save_as: index.html +sort: 0 + +The [Computer Science Club](https://csclub.uwaterloo.ca) is currently working on a private cloud environment (powered by [OpenStack](https://www.openstack.org)) to enhance our web hosting services. This will allow the club to offer private servers to our members. + +## Thanks to our donors + +Hardware for this project was provided by: + +- Funding from the [Mathematics Endowment Fund](https://uwaterloo.ca/math-endowment-fund/) +- Funding from the [Student Life Endowment Fund](https://feds.ca/funding#fund-slef) +- Hardware donations from club members diff --git a/content/pages/usage-agreement.md b/content/pages/usage-agreement.md new file mode 100644 index 0000000..bf3f10c --- /dev/null +++ b/content/pages/usage-agreement.md @@ -0,0 +1,88 @@ +title: Cloud (Beta) Usage Agreement +slug: usage-agreement + +*This agreement, in its current form, applies to those participating in the CSC +Cloud Beta. This agreement may change at any time, with notice, during the beta +period and may change prior to general availability.* + +## Introduction + +The use of this system is governed by the Computer Science Club's [Machine +Usage Agreement](https://csclub.uwaterloo.ca/services/machine_usage) +and [Code of Conduct](https://csclub.uwaterloo.ca/about/code-of-conduct). +Please take the time to review these documents before using this system. The +Computer Science Club Executive and Systems Committee are responsible for +enforcing these policies. + +This agreement is supplemental to the [Machine Usage +Agreement](https://csclub.uwaterloo.ca/services/machine_usage). It +acts primarily to emphasize certain points, but may add additional policies +specific to the Computer Science Club Cloud. + +## Use + +You may use this service for any purpose, except: + +1. Commericial purposes (ex. ads, your startup, etc.) +2. Violation of any usage agreement, University policy, or law + +### Eligibility + +You may only use this service if: + +1. Your membership is current, or +2. If you are a club representative, where use is for club purposes only + +### Email + +Under no circumstances shall unsolicited (ie. spam) email be sent using this +service. + +## Service Level Agreement + +### Uptime + +> **The Computer Science Club makes no guarantee of availability of the service.** + +We will do our best to keep the service available at all times, and provide +advanced notice of service. + +### Data Integrity + +> **The Computer Science Club makes no guarantee of data integrity.** + +It is your responsibility to ensure that you have appropriate backups of all +data stored on the service. We are not responsible for any lost data +whatsoever. + +## Auditing and Logging + +The Computer Science Club Systems Committee keeps records ("logs") on the +service to: + +1. Collect and store diagnostic information to aid in debugging hardware and + software issues; +2. Document manchine usage and activity; +3. Refer to for auditing purposes. + +### Network Address Translation + +The Computer Science Club uses Network Address Translation on IPv4 to allow +access to off-campus resources. All translations performed are logged with +source IP, destination IP, source port, destination port and timestamps +indicating the start and end of the translation. + +### Use of Records + +The logs contain records of user and machine activity. The Systems Committee +reserves the right to share these records with the University or local +law enforcement as required. + +## User Agreement + +I have read and understood the usage agreement of 16 August 2017, and I +agreee that my usage of the Computer Science Club will be in accordance with +this policy. I understand that I am responsible for all actions performed from +my account (or the services attached to it). Furthermore, I accept full legal +responsibility for all of the actions that I commit using the Computer Science +Club Cloud according to any and all applicable laws. diff --git a/content/pages/user-setup.md b/content/pages/user-setup.md new file mode 100644 index 0000000..7ea88b1 --- /dev/null +++ b/content/pages/user-setup.md @@ -0,0 +1,41 @@ +title: User Setup +slug: docs/admin/user-setup +status: hidden + +## Option 1 (Recommended) + +Use the `adduser.py` script, available at [https://git.uwaterloo.ca/zachary.seguin/csclub-cloud-scripts](https://git.uwaterloo.ca/zachary.seguin/csclub-cloud-scripts). + +## Option 2 + +### 1. LDAP Configuration + +A `userPassword` property must be added to a user's LDAP object before they can +successfully authenticate against our cloud environment. + +1. Open ldapvi `ldapvi -Y GSSAPI` +2. Find the user, and add: `userPassword: {SASL}@CSCLUB.UWATERLOO.CA` +3. Quit your editor +4. Type `y` to perform the changes + +### 2. Add user project + +All members will be assigned their own project. All instructions are executed +using the OpenStack command line client. + +1. `openstack project create --domain csclub ` +2. `openstack role --project --user user` + +### Appendix A: OpenStack Environment Variables + +```sh +export OS_USERNAME= +export OS_PASSWORD= +export OS_PROJECT_NAME=csc +export OS_USER_DOMAIN_NAME=csclub +export OS_PROJECT_DOMAIN_NAME=csclub +export OS_AUTH_URL=https://auth.cloud.csclub.uwaterloo.ca/v3 +export OS_IDENTITY_API_VERSION=3 +``` + +NOTE: To control your project, change `OS_PROJECT_NAME` to your username. diff --git a/develop_server.sh b/develop_server.sh new file mode 100755 index 0000000..4721d64 --- /dev/null +++ b/develop_server.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +## +# This section should match your Makefile +## +PY=${PY:-python3} +PELICAN=${PELICAN:-pelican} +PELICANOPTS= + +BASEDIR=$(pwd) +INPUTDIR=$BASEDIR/content +OUTPUTDIR=$BASEDIR/output +CONFFILE=$BASEDIR/pelicanconf.py + +### +# Don't change stuff below here unless you are sure +### + +SRV_PID=$BASEDIR/srv.pid +PELICAN_PID=$BASEDIR/pelican.pid + +function usage(){ + echo "usage: $0 (stop) (start) (restart) [port]" + echo "This starts Pelican in debug and reload mode and then launches" + echo "an HTTP server to help site development. It doesn't read" + echo "your Pelican settings, so if you edit any paths in your Makefile" + echo "you will need to edit your settings as well." + exit 3 +} + +function alive() { + kill -0 $1 >/dev/null 2>&1 +} + +function shut_down(){ + PID=$(cat $SRV_PID) + if [[ $? -eq 0 ]]; then + if alive $PID; then + echo "Stopping HTTP server" + kill $PID + else + echo "Stale PID, deleting" + fi + rm $SRV_PID + else + echo "HTTP server PIDFile not found" + fi + + PID=$(cat $PELICAN_PID) + if [[ $? -eq 0 ]]; then + if alive $PID; then + echo "Killing Pelican" + kill $PID + else + echo "Stale PID, deleting" + fi + rm $PELICAN_PID + else + echo "Pelican PIDFile not found" + fi +} + +function start_up(){ + local port=$1 + echo "Starting up Pelican and HTTP server" + shift + $PELICAN --debug --autoreload -r $INPUTDIR -o $OUTPUTDIR -s $CONFFILE $PELICANOPTS & + pelican_pid=$! + echo $pelican_pid > $PELICAN_PID + mkdir -p $OUTPUTDIR && cd $OUTPUTDIR + $PY -m pelican.server $port & + srv_pid=$! + echo $srv_pid > $SRV_PID + cd $BASEDIR + sleep 1 + if ! alive $pelican_pid ; then + echo "Pelican didn't start. Is the Pelican package installed?" + return 1 + elif ! alive $srv_pid ; then + echo "The HTTP server didn't start. Is there another service using port" $port "?" + return 1 + fi + echo 'Pelican and HTTP server processes now running in background.' +} + +### +# MAIN +### +[[ ($# -eq 0) || ($# -gt 2) ]] && usage +port='' +[[ $# -eq 2 ]] && port=$2 + +if [[ $1 == "stop" ]]; then + shut_down +elif [[ $1 == "restart" ]]; then + shut_down + start_up $port +elif [[ $1 == "start" ]]; then + if ! start_up $port; then + shut_down + fi +else + usage +fi diff --git a/fabfile.py b/fabfile.py new file mode 100644 index 0000000..b3a0222 --- /dev/null +++ b/fabfile.py @@ -0,0 +1,92 @@ +from fabric.api import * +import fabric.contrib.project as project +import os +import shutil +import sys +import SocketServer + +from pelican.server import ComplexHTTPRequestHandler + +# Local path configuration (can be absolute or relative to fabfile) +env.deploy_path = 'output' +DEPLOY_PATH = env.deploy_path + +# Remote server configuration +production = 'root@localhost:22' +dest_path = '/var/www' + +# Rackspace Cloud Files configuration settings +env.cloudfiles_username = 'my_rackspace_username' +env.cloudfiles_api_key = 'my_rackspace_api_key' +env.cloudfiles_container = 'my_cloudfiles_container' + +# Github Pages configuration +env.github_pages_branch = "gh-pages" + +# Port for `serve` +PORT = 8000 + +def clean(): + """Remove generated files""" + if os.path.isdir(DEPLOY_PATH): + shutil.rmtree(DEPLOY_PATH) + os.makedirs(DEPLOY_PATH) + +def build(): + """Build local version of site""" + local('pelican -s pelicanconf.py') + +def rebuild(): + """`build` with the delete switch""" + local('pelican -d -s pelicanconf.py') + +def regenerate(): + """Automatically regenerate site upon file modification""" + local('pelican -r -s pelicanconf.py') + +def serve(): + """Serve site at http://localhost:8000/""" + os.chdir(env.deploy_path) + + class AddressReuseTCPServer(SocketServer.TCPServer): + allow_reuse_address = True + + server = AddressReuseTCPServer(('', PORT), ComplexHTTPRequestHandler) + + sys.stderr.write('Serving on port {0} ...\n'.format(PORT)) + server.serve_forever() + +def reserve(): + """`build`, then `serve`""" + build() + serve() + +def preview(): + """Build production version of site""" + local('pelican -s publishconf.py') + +def cf_upload(): + """Publish to Rackspace Cloud Files""" + rebuild() + with lcd(DEPLOY_PATH): + local('swift -v -A https://auth.api.rackspacecloud.com/v1.0 ' + '-U {cloudfiles_username} ' + '-K {cloudfiles_api_key} ' + 'upload -c {cloudfiles_container} .'.format(**env)) + +@hosts(production) +def publish(): + """Publish to production via rsync""" + local('pelican -s publishconf.py') + project.rsync_project( + remote_dir=dest_path, + exclude=".DS_Store", + local_dir=DEPLOY_PATH.rstrip('/') + '/', + delete=True, + extra_opts='-c', + ) + +def gh_pages(): + """Publish to GitHub Pages""" + rebuild() + local("ghp-import -b {github_pages_branch} {deploy_path} -p".format(**env)) diff --git a/pelicanconf.py b/pelicanconf.py new file mode 100644 index 0000000..30e06d7 --- /dev/null +++ b/pelicanconf.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- # +from __future__ import unicode_literals + +AUTHOR = 'Calum T. Dalek' +SITENAME = 'Computer Science Club Cloud' +SITEURL = '' + +THEME = 'themes/csclub' +PATH = 'content' + +PAGE_URL = '{slug}/' +PAGE_SAVE_AS = '{slug}/index.html' + +TIMEZONE = 'Canada/Eastern' + +DEFAULT_LANG = 'en' + +# Feed generation is usually not desired when developing +FEED_ALL_ATOM = None +CATEGORY_FEED_ATOM = None +TRANSLATION_FEED_ATOM = None +AUTHOR_FEED_ATOM = None +AUTHOR_FEED_RSS = None + +# Main menu +# MENUITEMS = (('CSC Cloud', '/'), +DISPLAY_PAGES_ON_MENU = True +DISPLAY_CATEGORIES_ON_MENU = False +PAGE_ORDER_BY = 'sort' + +# Blogroll +LINKS = (('Pelican', 'http://getpelican.com/'), + ('Python.org', 'http://python.org/'), + ('Jinja2', 'http://jinja.pocoo.org/'), + ('You can modify those links in your config file', '#'),) + +# Social widget +SOCIAL = (('You can add links in your config file', '#'), + ('Another social link', '#'),) + +DEFAULT_PAGINATION = 10 + +# Uncomment following line if you want document-relative URLs when developing +#RELATIVE_URLS = True diff --git a/publishconf.py b/publishconf.py new file mode 100644 index 0000000..3ded804 --- /dev/null +++ b/publishconf.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- # +from __future__ import unicode_literals + +# This file is only used if you use `make publish` or +# explicitly specify it as your config file. + +import os +import sys +sys.path.append(os.curdir) +from pelicanconf import * + +SITEURL = 'https://cloud.csclub.uwaterloo.ca' +RELATIVE_URLS = False + +FEED_ALL_ATOM = 'feeds/all.atom.xml' +CATEGORY_FEED_ATOM = 'feeds/%s.atom.xml' + +DELETE_OUTPUT_DIRECTORY = True + +# Following items are often useful when publishing + +#DISQUS_SITENAME = "" +#GOOGLE_ANALYTICS = "" diff --git a/themes/csclub/static/css/main.css b/themes/csclub/static/css/main.css new file mode 100644 index 0000000..6a04e68 --- /dev/null +++ b/themes/csclub/static/css/main.css @@ -0,0 +1,101 @@ +body { + font-family: sans-serif; + font-size: 14px; +} + +body > header { + display: flex; + justify-content: center; + padding: 15px 0; +} + +body > header, +body > nav, +.content-wrapper, +body > footer { + max-width: 100%; + width: 920px; + margin: 0 auto; +} + +body > nav { + background: #215498; + border-radius: 4px; + background-clip: border-box; +} + +body > nav ul { + list-style: none; + margin: 0; + padding: 0; + overflow: hidden; +} + +body > nav li { + float: left; +} + +body > nav a { + display: inline-block; + color: white; + text-decoration: none; + padding: 10px; +} + +body > nav a:hover, +body > nav .active a { + text-decoration: underline; +} + +body > nav ul li:first-child a { + font-weight: bold; +} + +.uw_logo { + width: 250px; +} + +.csc_logo { + height: 100px; +} + +body > footer { + font-size: 0.9em; + text-align: center; + color: #444; + + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid #ccc; +} + +a { + color: #215499; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +p, li { + line-height: 1.4em; +} + +.highlight, code { + background: #eee; + border-radius: 6px; +} + +code { + padding: 0px 6px; +} + +.highlight { + padding: 4px 10px; + border: 1px solid #aaa; +} + +.highlight .nv { color: green; } +.highlight .nb { color: #aa0000; } +.highlight .o { color: #0000aa; } diff --git a/themes/csclub/static/images/csc_logo.png b/themes/csclub/static/images/csc_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..09e58f504b56f4195186f7c71241a17a0a9ebfd6 GIT binary patch literal 14247 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�Emp{3W!FRjkxzv!tW1S88Mb& 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 + + + + + + + + + image/svg+xml + + + + + + + COMPUTER SCIENCE CLUB + + + diff --git a/themes/csclub/static/images/uw_logo.png b/themes/csclub/static/images/uw_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f518188c1c11e610c4ed758f0c0d11d9b9546886 GIT binary patch literal 21100 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 literal 0 HcmV?d00001 diff --git a/themes/csclub/static/images/uw_logo.svg b/themes/csclub/static/images/uw_logo.svg new file mode 100644 index 0000000..a72c354 --- /dev/null +++ b/themes/csclub/static/images/uw_logo.svg @@ -0,0 +1,247 @@ + +image/svg+xml \ No newline at end of file diff --git a/themes/csclub/templates/archives.html b/themes/csclub/templates/archives.html new file mode 100644 index 0000000..050f268 --- /dev/null +++ b/themes/csclub/templates/archives.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block content %} +

Archives for {{ SITENAME }}

+ +
+{% for article in dates %} +
{{ article.locale_date }}
+
{{ article.title }}
+{% endfor %} +
+{% endblock %} diff --git a/themes/csclub/templates/article.html b/themes/csclub/templates/article.html new file mode 100644 index 0000000..fb01b33 --- /dev/null +++ b/themes/csclub/templates/article.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} +{% block head %} + {{ super() }} + {% if article.description %} + + {% endif %} + + {% for tag in article.tags %} + + {% endfor %} + +{% endblock %} + +{% block content %} +
+
+

+ {{ article.title }}

+ {% import 'translations.html' as translations with context %} + {{ translations.translations_for(article) }} +
+
+ + {% if article.modified %} + + {% endif %} + {% if article.authors %} +
+ By {% for author in article.authors %} + {{ author }} + {% endfor %} +
+ {% endif %} +
+
+ {{ article.content }} +
+
+{% endblock %} diff --git a/themes/csclub/templates/author.html b/themes/csclub/templates/author.html new file mode 100644 index 0000000..e9f7870 --- /dev/null +++ b/themes/csclub/templates/author.html @@ -0,0 +1,7 @@ +{% extends "index.html" %} + +{% block title %}{{ SITENAME }} - Articles by {{ author }}{% endblock %} +{% block content_title %} +

Articles by {{ author }}

+{% endblock %} + diff --git a/themes/csclub/templates/authors.html b/themes/csclub/templates/authors.html new file mode 100644 index 0000000..4914904 --- /dev/null +++ b/themes/csclub/templates/authors.html @@ -0,0 +1,13 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME }} - Authors{% endblock %} + +{% block content %} +

Authors on {{ SITENAME }}

+ +
    + {%- for author, articles in authors|sort %} +
  • {{ author }} ({{ articles|count }})
  • + {% endfor %} +
+{% endblock %} diff --git a/themes/csclub/templates/base.html b/themes/csclub/templates/base.html new file mode 100644 index 0000000..994ed40 --- /dev/null +++ b/themes/csclub/templates/base.html @@ -0,0 +1,78 @@ + + + + {% block head %} + + + + {% block title %}{{ SITENAME }}{% endblock title %} | {{ SITENAME }} + + + {% if FEED_ALL_ATOM %} + + {% endif %} + {% if FEED_ALL_RSS %} + + {% endif %} + {% if FEED_ATOM %} + + {% endif %} + {% if FEED_RSS %} + + {% endif %} + {% if CATEGORY_FEED_ATOM and category %} + + {% endif %} + {% if CATEGORY_FEED_RSS and category %} + + {% endif %} + {% if TAG_FEED_ATOM and tag %} + + {% endif %} + {% if TAG_FEED_RSS and tag %} + + {% endif %} + {% endblock head %} + + + +
+ + + +
+ + + +
+ {% block content %} + {% endblock %} +
+ + + + diff --git a/themes/csclub/templates/categories.html b/themes/csclub/templates/categories.html new file mode 100644 index 0000000..e29be0c --- /dev/null +++ b/themes/csclub/templates/categories.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% block content %} +
    +{% for category, articles in categories %} +
  • {{ category }}
  • +{% endfor %} +
+{% endblock %} diff --git a/themes/csclub/templates/category.html b/themes/csclub/templates/category.html new file mode 100644 index 0000000..4e6fd24 --- /dev/null +++ b/themes/csclub/templates/category.html @@ -0,0 +1,5 @@ +{% extends "index.html" %} +{% block content_title %} +

Articles in the {{ category }} category

+{% endblock %} + diff --git a/themes/csclub/templates/gosquared.html b/themes/csclub/templates/gosquared.html new file mode 100644 index 0000000..49ccbbe --- /dev/null +++ b/themes/csclub/templates/gosquared.html @@ -0,0 +1,14 @@ +{% if GOSQUARED_SITENAME %} + +{% endif %} diff --git a/themes/csclub/templates/index.html b/themes/csclub/templates/index.html new file mode 100644 index 0000000..ab4bc34 --- /dev/null +++ b/themes/csclub/templates/index.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% block content %} +
+{% block content_title %} +

All articles

+{% endblock %} + +
    +{% for article in articles_page.object_list %} +
  1. +

    {{ article.title }}

    +
    + +
    By + {% for author in article.authors %} + {{ author }} + {% endfor %} +
    +
    +
    {{ article.summary }}
    +
  2. +{% endfor %} +
+{% if articles_page.has_other_pages() %} + {% include 'pagination.html' %} +{% endif %} +
+{% endblock content %} diff --git a/themes/csclub/templates/page.html b/themes/csclub/templates/page.html new file mode 100644 index 0000000..5ceb779 --- /dev/null +++ b/themes/csclub/templates/page.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} +{% block title %}{{ page.title }}{%endblock%} +{% block content %} +

{{ page.title }}

+ {% import 'translations.html' as translations with context %} + {{ translations.translations_for(page) }} + + {{ page.content }} + + {% if page.modified %} +

+ Last updated: {{ page.locale_modified }} +

+ {% endif %} +{% endblock %} diff --git a/themes/csclub/templates/pagination.html b/themes/csclub/templates/pagination.html new file mode 100644 index 0000000..4219a5c --- /dev/null +++ b/themes/csclub/templates/pagination.html @@ -0,0 +1,11 @@ +{% if DEFAULT_PAGINATION %} +

+ {% if articles_page.has_previous() %} + « + {% endif %} + Page {{ articles_page.number }} / {{ articles_paginator.num_pages }} + {% if articles_page.has_next() %} + » + {% endif %} +

+{% endif %} diff --git a/themes/csclub/templates/period_archives.html b/themes/csclub/templates/period_archives.html new file mode 100644 index 0000000..d930dbb --- /dev/null +++ b/themes/csclub/templates/period_archives.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} +{% block content %} +

Archives for {{ period | reverse | join(' ') }}

+ +
+{% for article in dates %} +
{{ article.locale_date }}
+
{{ article.title }}
+{% endfor %} +
+{% endblock %} diff --git a/themes/csclub/templates/tag.html b/themes/csclub/templates/tag.html new file mode 100644 index 0000000..e69de29 diff --git a/themes/csclub/templates/tags.html b/themes/csclub/templates/tags.html new file mode 100644 index 0000000..b5d1482 --- /dev/null +++ b/themes/csclub/templates/tags.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block title %}{{ SITENAME }} - Tags{% endblock %} + +{% block content %} +

Tags for {{ SITENAME }}

+ {%- for tag, articles in tags|sort %} +
  • {{ tag }} ({{ articles|count }})
  • + {% endfor %} +{% endblock %} diff --git a/themes/csclub/templates/translations.html b/themes/csclub/templates/translations.html new file mode 100644 index 0000000..db8c372 --- /dev/null +++ b/themes/csclub/templates/translations.html @@ -0,0 +1,9 @@ +{% macro translations_for(article) %} +{% if article.translations %} +Translations: +{% for translation in article.translations %} +{{ translation.lang }} +{% endfor %} +{% endif %} +{% endmacro %} +