commit 23357dfd208cc0176602c803b6f98566e3064243 Author: Zachary Seguin Date: Sat Aug 11 11:30:26 2018 -0400 Initial commit 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 0000000..09e58f5 Binary files /dev/null and b/themes/csclub/static/images/csc_logo.png differ diff --git a/themes/csclub/static/images/csc_logo.svg b/themes/csclub/static/images/csc_logo.svg new file mode 100644 index 0000000..a7e70a7 --- /dev/null +++ b/themes/csclub/static/images/csc_logo.svg @@ -0,0 +1,94 @@ + + + + + + + + + + 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 0000000..f518188 Binary files /dev/null and b/themes/csclub/static/images/uw_logo.png differ 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 %} +