contact form, newer styles and various other tweaks

This commit is contained in:
Oliver Marks 2016-08-20 19:45:28 +01:00
parent 7470d0f364
commit c213dd0811
132 changed files with 1683 additions and 1404 deletions

View File

@ -1,34 +1,52 @@
# fabricad
#
# VERSION 0.0.1
FROM olymk2/uwsgi
FROM ubuntu:16.04
MAINTAINER Oliver Marks "olymk2@gmail.com"
ENV SERVER_ENVIRONMENT DEVELOPMENT
ENV SITE_FOLDER /etc/sites/mysite/
ENV SERVER_ENVIRONMENT DOCKER
#COPY website/config/nginx/maidstone-hackspace.org.uk.ini /etc/sites/nginx/maidstone-hackspace.org.uk.ini
#COPY website/config/uwsgi/maidstone-hackspace.org.uk.ini /etc/sites/uwsgi/maidstone-hackspace.org.uk.ini
RUN apk add --update --no-cache libssl1.0 libxml2 libxslt ca-certificates
RUN apk add --update --no-cache py-psycopg2 py-lxml py-flask py-pillow py-openssl py-cffi
RUN apk add --update --no-cache build-base make bzr python3-dev libffi-dev openssl-dev libxml2-dev libxslt-dev && \
pip3 install lxml && \
pip3 install --no-cache-dir lxml dateutils requests requests-oauthlib mailer gocardless paypalrestsdk pytz nose2 oauthlib flask flask-login pymysql misaka && \
pip3 install --no-cache-dir bzr+lp:scaffold/trunk#egg=scaffold && \
apk del build-base make bzr python3-dev libffi-dev openssl-dev libxml2-dev libxslt-dev
# RUN pip3 install --no-cache-dir dateutils requests requests-oauthlib gocardless paypalrestsdk pytz nose2 oauthlib flask flask-login pymysql misaka
# RUN pip3 install --no-cache-dir bzr+lp:scaffold/trunk#egg=scaffold
#CMD ["setup.sh"]
#ENTRYPOINT ["setup.sh"]
# make sure the package repository is up to date
RUN \
apt-get update && \
apt-get upgrade -y && \
apt-get install -y libssl-dev libffi-dev nano && \
apt-get install -y software-properties-common python-software-properties && \
apt-get install -y software-properties-common python-pip python-dev python-nose2 && \
apt-get install -y python-mysqldb python-psycopg2 python-requests-oauthlib python-dateutil python-requests python-lxml python-flask python-flask-login python-pillow && \
apt-get install -y cssmin slimit && \
add-apt-repository -y ppa:oly/ppa && \
apt-get update && \
apt-get install -y python-scaffold
#RUN \
# apt-get update && \
# apt-get upgrade -y && \
# apt-get install -y libssl-dev libffi-dev nano && \
# apt-get install -y software-properties-common python-software-properties && \
# apt-get install -y software-properties-common python-pip python-dev python-nose2 && \
# apt-get install -y python-mysqldb python-psycopg2 python-requests-oauthlib python-dateutil python-requests python-lxml python-flask python-flask-login python-pillow && \
# apt-get install -y cssmin slimit && \
# add-apt-repository -y ppa:oly/ppa && \
# apt-get update && \
# apt-get install -y python-scaffold
RUN pip install gocardless paypalrestsdk pytz
#allow access to flask
EXPOSE 5000 5002
WORKDIR /var/www/website/
#EXPOSE 5000 5002
#WORKDIR /var/www/website/
#RUN /bin/sh -c 'cd /var/www/site; python index.py'
ENTRYPOINT /bin/sh -c 'python index.py'
#ENTRYPOINT /bin/sh -c 'scaffold import && python index.py'
#docker build -t mhackspace .
#docker run -d --name=mhackspace_container --restart=always mhackspace
#docker run -it -v /etc/uwsgi/apps-enabled/:/etc/uwsgi/apps-enabled/ -v sockets:/data/sockets --entrypoint sh --name mhackspace olymk2/mhackspace
#docker run -it -v /etc/uwsgi/apps-enabled/:/etc/uwsgi/apps-enabled/ -v sockets:/data/sockets -v /var/www/test.maidstone-hackspace.org.uk/site:/var/www --name mhackspace olymk2/mhackspace
#accesss on dockerip 172.17.0.?:5000
#https://hub.docker.com/r/olymk2/mhackspace/

View File

@ -14,6 +14,9 @@ The simplest way to setup this site is to use docker-compose so please install t
and make sure the quick start guide works https://docs.docker.com/machine/get-started/ then you can use the commands below to test and make changes.
docker-compose up
docker volume create --name sockets
docker run -it -v /etc/uwsgi/apps-enabled/:/etc/uwsgi/apps-enabled/ -v /var/www:/var/www -v sockets:/data/sockets --name mhackspace olymk2/mhackspace
If you plan on making large changes consider discussing it first so you dont waste your own time.

View File

@ -0,0 +1,3 @@
PATH=/usr/local/sbin:/usr/local/bin
MAILTO=contact@maidstone-hackspace.org.uk
0 2 * * * python /var/www/maidstone-hackspace.org.uk/site/generate.py

View File

@ -0,0 +1,2 @@
./letsencrypt-auto certonly -d maidstone-hackspace.org.uk -d live.maidstone-hackspace.org.uk
./letsencrypt-auto certonly -d test.maidstone-hackspace.org.uk

View File

@ -0,0 +1,28 @@
server {
listen 80;
server_name maidstone-hackspace.org.uk live.maidstone-hackspace.org.uk www.maidstone-hackspace.org.uk;
root /var/www/static/html;
error_page 404 = /404.htm;
location = / {
# match uri equalling / only for index, if anything is after / go to next location
try_files $uri $uri/index.htm;
}
location / {
# if the first root location fails try this one instead and fallback to uwsgi
try_files $uri $uri.htm $uri/ @uwsgi_fallback;
#error_page 404 = @fallback;
}
location /static/ {
alias /var/www/static/;
log_not_found on;
}
location @uwsgi_fallback {
include uwsgi_params;
uwsgi_pass unix:///data/sockets/maidstone_hackspace.sock;
}
}

View File

@ -0,0 +1,105 @@
server {
listen 443 ssl http2;
server_name maidstone-hackspace.org.uk live.maidstone-hackspace.org.uk www.maidstone-hackspace.org.uk;
root /var/www/live-maidstone-hackspace.org.uk/site/html;
ssl_certificate /etc/letsencrypt/live/live.maidstone-hackspace.org.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/live.maidstone-hackspace.org.uk/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
resolver 8.8.8.8;
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security max-age=15768000;
error_page 404 = /404.htm;
location = / {
# match uri equalling / only for index, if anything is after / go to next location
try_files $uri $uri/index.htm;
}
location / {
try_files $uri $uri.htm $uri/ @uwsgi_fallback;
#error_page 404 = @fallback;
}
location /static {
alias /var/www/live-maidstone-hackspace.org.uk/site/static;
#expires 1d;
#add_header Pragma public;
#add_header Cache-Control "public";
}
location @uwsgi_fallback {
include uwsgi_params;
uwsgi_pass unix:///data/sockets/live-maidstone_hackspace.sock;
}
}
server {
listen 443 ssl http2;
server_name test.maidstone-hackspace.org.uk;
root /var/www/test-maidstone-hackspace.org.uk/site/html;
ssl_certificate /etc/letsencrypt/live/test.maidstone-hackspace.org.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test.maidstone-hackspace.org.uk/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_protocols TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
resolver 8.8.8.8;
server_tokens off;
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security max-age=15768000;
error_page 404 = /404.htm;
location = / {
# match uri equalling / only for index, if anything is after / go to next location
try_files $uri $uri/index.htm;
}
location / {
try_files $uri $uri.htm $uri/ @uwsgi_fallback;
#error_page 404 = @fallback;
}
location /static {
alias /var/www/test-maidstone-hackspace.org.uk/site/static;
expires 1d;
add_header Pragma public;
add_header Cache-Control "public";
}
location @uwsgi_fallback {
include uwsgi_params;
uwsgi_pass unix:///data/sockets/test-maidstone_hackspace.sock;
}
}

View File

@ -0,0 +1,16 @@
[uwsgi]
module = wsgi
chdir = /var/www/
base = /var/www/
touch-reload = /etc/uwsgi/apps-enabled/maidstone-hackspace.org.uk.ini
master = true
processes = 3
logto = /tmp/maidstone_hackspace.log
plugin = python3
socket = /data/sockets/maidstone_hackspace.sock
chmod-socket = 660
vacuum = true
die-on-term = true
# only for development
python-autoreload = 3

View File

@ -1,25 +1,50 @@
version: '2'
nginx:
image: olymk2/mhackspace
#name: mhackspace
links:
- db:database
dns:
- 8.8.8.8
- 8.8.4.4
ports:
- "5000:5000"
volumes:
- .:/var/www
restart: always
services:
mhackspace_uwsgi:
image: olymk2/mhackspace
restart: unless-stopped
network_mode: bridge
links:
- mariadb:mariadb
- mhackspace_web:nginx
- mhackspace_mail:mail_server
volumes:
- sockets:/data/sockets
- ./website/:/var/www
- ./config/uwsgi/maidstone-hackspace.org.uk.ini:/etc/uwsgi/apps-enabled/maidstone-hackspace.org.uk.ini
db:
image: mariadb
ports:
- "3300:3306"
environment:
MYSQL_DATABASE: maidstone_hackspace
MYSQL_USER: mhackspace
MYSQL_PASSWORD: mhackspace
MYSQL_ROOT_PASSWORD: mhackspace
restart: always
mhackspace_web:
image: olymk2/nginx
restart: unless-stopped
network_mode: bridge
dns:
- 8.8.8.8
- 8.8.4.4
volumes:
- ./website/:/var/www
- sockets:/data/sockets
- /etc/ssl/certs/:/etc/ssl/certs/
- ./config/nginx/docker-maidstone-hackspace.org.uk:/etc/nginx/sites-enabled/docker-maidstone-hackspace.org.uk
restart: always
mariadb:
image: mariadb
network_mode: bridge
ports:
- "3300:3306"
environment:
MYSQL_DATABASE: maidstone_hackspace
MYSQL_USER: mhackspace
MYSQL_PASSWORD: mhackspace
MYSQL_ROOT_PASSWORD: mhackspace
restart: unless-stopped
mhackspace_mail:
image: mailhog/mailhog
network_mode: bridge
restart: unless-stopped
volumes:
sockets:
driver: local

View File

@ -1,409 +0,0 @@
import os
import uuid
import hashlib
import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from flask import session, flash
from flask import redirect, abort
from flask import make_response
from flask import request
from flask import Blueprint
from flask.ext.login import current_user, LoginManager, login_required, UserMixin, login_user, logout_user, make_secure_token
from requests_oauthlib import OAuth2Session
from requests_oauthlib.compliance_fixes import facebook_compliance_fix
from scaffold import web
from libs.mail import sendmail
from pages import header, footer
from data import site_user
from config.settings import *
from constants import *
web.load_widgets('widgets')
authorize_pages = Blueprint('authorize_pages', __name__, template_folder='templates')
login_manager = LoginManager()
login_manager.login_view = '/login'
oauth_lookup = {'google':1, 'github':2, 'facebook':3}
def is_weak_password(password1, password2):
if password1 != password2:
password1 = password2 = None
return True
# TODO check length and chars
password1 = password2 = None
return False
def todict(data):
new_dict = {}
for key, value in data.items():
new_dict[key] = value
return new_dict
class User(UserMixin):
def __init__(self, user_id, active=True):
print user_id
self.id = None
user_details = site_user.get_user_details({'id': user_id}).get()
self.active = False
print 'user'
print user_details
if user_details:
#~ self.check_password(user_details.get('password'))
self.id = user_id
self.name = user_details.get('username')
print self.name
self.active = active
def get_id(self):
return self.id
def is_active(self):
return self.active
def is_authenticated(self):
return self.active
def get_auth_token(self):
return make_secure_token(self.name, key='deterministic')
@login_manager.user_loader
def load_user(userid):
"""Flask user loader hook, internal to flask login"""
return User(userid)
@login_manager.token_loader
def load_token(request):
token = request.headers.get('Authorization')
if token is None:
token = request.args.get('token')
if token is not None:
username, password = token.split(":") # naive token
print username
print password
user_entry = User.get(username)
if (user_entry is not None):
user = User(user_entry[0], user_entry[1])
if (user.password == password):
return user
return None
#~ def auth_required():
#~ if not session.get('user_id'):
#~ redirect(domain + '/login', 301)
@authorize_pages.route("/register", methods=['GET'])
def register_form():
header('Register for access')
web.page.create('Register for access')
#~ web.page.section(web.register_form.create().render())
web.form.create('Register new user account', '/register')
web.form.append(name='name', label='Your full name', placeholder='Ralf Green', value='')
web.form.append(name='email', label='Valid Email', placeholder='ralf@maidstone-hackspace.org.uk', value='')
web.form.append(input_type='password', name='password', label='Password', placeholder='quick brown fox jumped over', value='')
web.form.append(input_type='password', name='password_confirm', label='Password Confirm', placeholder='quick brown fox jumped over', value='')
web.page.section(web.form.render())
web.template.body.append(web.page.render())
return make_response(footer())
@authorize_pages.route("/register", methods=['POST'])
def register_submit():
data = {}
data['email'] = request.form.get('email')
data['username'] = request.form.get('email')
data['first_name'] = request.form.get('name').strip().split()[0]
data['last_name'] = request.form.get('name').strip().split()[-1]
data['password'] = request.form.get('password')
data['password_confirm'] = request.form.get('password')
data['password'] = generate_password_hash(request.form.get('password'))
#TODO password strength tests
if is_weak_password(request.form.get('password'), request.form.get('password_confirm')):
redirect('/register')
header('Your account has been registered')
web.page.create('Your account has been registered')
new_user = site_user.create()
new_user.execute(data)
flash('Your account has now been created')
web.template.body.append(web.page.render())
return make_response(footer())
@authorize_pages.route("/oauth/<provider>/<start_oauth_login>/", methods=['GET'])
@authorize_pages.route("/oauth/<provider>/<start_oauth_login>", methods=['GET'])
@authorize_pages.route("/oauth/<provider>/", methods=['GET'])
@authorize_pages.route("/oauth/<provider>", methods=['GET'])
def oauth(provider, start_oauth_login=False):
oauth_verify = True
oauth_provider = oauth_conf.get(provider)
oauth_access_type = ''
oauth_approval_prompt = ''
if oauth_live is False:
oauth_verify = False
oauth_access_type = 'offline'
oauth_approval_prompt = "force"
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
if start_oauth_login:
print oauth_provider.get('redirect_uri')
oauth_session = OAuth2Session(
oauth_provider.get('client_id'),
scope=oauth_provider.get('scope'),
redirect_uri=oauth_provider.get('redirect_uri'))
if provider == 'facebook':
oauth_session = facebook_compliance_fix(oauth_session)
authorization_url, state = oauth_session.authorization_url(
oauth_provider.get('auth_uri'),
access_type=oauth_access_type,
approval_prompt=oauth_approval_prompt)
# State is used to prevent CSRF, keep this for later, make sure oauth returns to the same url.
# if testing and oauth_state errors make sure you logged in with localhost and not 127.0.0.1
session['oauth_state'] = state
session.modified = True
return redirect(authorization_url)
# allready authorised so lets handle the callback
oauth_session = OAuth2Session(
oauth_provider.get('client_id'),
state=session['oauth_state'],
redirect_uri=oauth_provider.get('redirect_uri'))
print '----------'
print oauth_provider.get('redirect_uri')
print request.url
if provider == 'facebook':
oauth_session = facebook_compliance_fix(oauth_session)
# code error is todo with authorisation response
oauth_session.fetch_token(
oauth_provider.get('token_uri'),
client_secret=oauth_provider.get('client_secret'),
authorization_response=request.url,
verify=oauth_verify)
# Fetch a protected resource, i.e. user profile
response = oauth_session.get(oauth_provider.get('user_uri'))
oauth_response = response.json()
print 'oauth response'
print oauth_response
oauth_id = oauth_response.get('login') or oauth_response.get('id')
provider_id = oauth_lookup.get(provider)
oauth_user = site_user.fetch_oauth_login({
'username': oauth_id or '',
'provider': provider_id
}).get()
if oauth_user:
user_details = site_user.get_user_details({
'id': oauth_user.get('user_id')
}).get()
# we have matched a user so login and redirect
if user_details:
login_user(User(user_details.get('user_id')))
# no E-Mail so lets ask the user to set there email before allowing login
if not user_details.get('email'):
return redirect('/profile/change_email')
return redirect('/profile')
flash('Your new profile has been created, and your now logged in')
print 'current user'
print current_user.get_id()
if current_user.get_id():
# link oauth to users account
site_user.create_oauth_login().execute({
'user_id': current_user.get_id(),
'username': oauth_id or '',
'provider': provider_id})
return redirect('/profile')
print oauth_response
print '-----'
print oauth_response.get('email') or ''
# create new user from oauth information
new_user_details = {
'password': 'oauth',
'profile_image': oauth_response.get('picture'),
'username': oauth_id,
'first_name': oauth_response.get('given_name') or '',
'last_name': oauth_response.get('family_name') or ''}
if oauth_response.get('email'):
new_user_details['email']= oauth_response.get('email')
user_id = site_user.create().execute(new_user_details)
# register oauth login creation
site_user.create_oauth_login().execute({
'user_id': user_id,
'username': oauth_id or '',
'provider': provider_id})
login_user(User(user_id))
site_user.update_last_login().execute({'id': user_id})
if not user_id:
flash('Failed to create user')
return redirect('/login')
return redirect('/profile')
@authorize_pages.route("/change-password/<code>", methods=['GET'])
@authorize_pages.route("/change-password", methods=['GET'])
def change_password(code=None):
#if we have a code this is a password reset, so try and login the user first
print code
site_user.delete_password_reset().execute({})
if code:
user_details = site_user.get_user_by_reset_code({'reset_code': code}).get()
print user_details
if not user_details:
#invalid code so pretend the page does not even exist
return abort(404)
#check the code has not expired
#datetime.datetime.now() + datetime.timedelta(minutes=15)
has_date_expired = user_details.get('created') + datetime.timedelta(minutes=60)
if has_date_expired < datetime.datetime.now():
print 'date expired'
#date expired so clean up and pretend the page does not exist
return abort(404)
#challenge passed so login the user so they can change there password
login_user(
User(user_details.get('user_id'))
)
session['user_id'] = str(user_details.get('user_id'))
web.template.create('Maidstone Hackspace - Profile')
header('User profile')
web.page.create('Change password')
web.page.section(
web.change_password_box.create().render()
)
web.template.body.append(web.page.render())
return make_response(footer())
@login_required
@authorize_pages.route("/change-password", methods=['POST'])
def change_password_submit(code=None):
if not session.get('user_id'):
abort(404)
user_details = site_user.authorize({
'id': session.get('user_id')}).get()
if is_weak_password(request.form.get('password'), request.form.get('password_confirm')):
print 'password not strong enough'
redirect('/login')
pw_hash = generate_password_hash(request.form.get('password'))
site_user.change_password().execute({'id': user_details.get('user_id'), 'password': pw_hash})
web.template.create('Maidstone Hackspace - Profile')
header('User Profile')
web.page.create('Password change complete')
web.page.section(
'Your password has successfull been changed'
)
web.template.body.append(web.page.render())
return make_response(footer())
@authorize_pages.route("/reset-password", methods=['GET'])
def reset_password():
web.template.create('Maidstone Hackspace - Login')
header('Members Login')
web.page.create('Forgot password reset')
web.page.section(
web.password_box.create('Please enter your E-Mail account', reset=True).render()
)
web.template.body.append(web.page.render())
return make_response(footer())
@authorize_pages.route("/reset-password", methods=['POST'])
def reset_password_submit():
user_details = site_user.get_by_username({
'email': request.form.get('email')}).get()
reset_code = hashlib.sha256(str(uuid.uuid4())).hexdigest()
if user_details:
site_user.create_password_reset() \
.on_duplicate() \
.execute({
'user_id': str(user_details.get('user_id')),
'reset_code': reset_code})
l=web.link.create(title='Change password', content='Click to change password',link="{domain}change-password/{resetcode}".format(**{'domain':app_domain, 'resetcode': reset_code})).render()
body = "Please follow the link below to change your password.\n" + l
body += "{domain}change-password/{resetcode}".format(**{'domain':app_domain, 'resetcode': reset_code})
sendmail().send(
from_address='no-reply@maidstone-hackspace.org.uk',
to_address='oly@leela',
subject="Reset password request",
body=body)
# display success page, dont give away anything about if the email is actually registered
web.template.create('Maidstone Hackspace - Password reset')
header('Password reset')
web.page.create('Password reset sent')
web.page.section(
web.paragraph.create('If this E-Mail is registered you will shortly be reciving an E-Mail with reset details').render()
)
web.template.body.append(web.page.render())
return make_response(footer())
#~ @authorize_pages.route("/login", methods=['GET'])
#~ def login_screen():
#~ web.template.create('Maidstone Hackspace - Login')
#~ header('Members Login')
#~ web.page.create('Member Login')
#~ web.page.section(
#~ web.login_box.create().enable_oauth('google').enable_oauth('facebook').enable_oauth('github').render()
#~ )
#~ web.template.body.append(web.page.render())
#~ return make_response(footer())
@authorize_pages.route("/login/failure", methods=['GET'])
def login_Failure():
web.template.create('%s - Login' % site_name)
header('Login Failure')
web.page.create('Login Failure')
#~ web.template.body.append(web.messages.render())
web.template.body.append(web.page.render())
return make_response(footer())
@authorize_pages.route("/logout")
def logout():
logout_user()
return redirect('/')

10
website/config/logger.py Normal file
View File

@ -0,0 +1,10 @@
import os
import logging
log = logging.getLogger('Maidstone Hackspace')
log.setLevel(logging.DEBUG)
#~ log.propagate = False
if os.path.exists('/tmp/maidstone_hackspace.log'):
ch = logging.FileHandler('/tmp/maidstone_hackspace.log')
ch.setLevel(logging.DEBUG)
log.addHandler(ch)

View File

@ -1,6 +1,10 @@
import os
import constants
import socket
from scaffold.core.data.database import db
from scaffold import web
from libs import mail
schema = 'https:'
domain = '127.0.0.1'
@ -35,27 +39,27 @@ google_calendar_api_key = ''
if os.environ.get('SERVER_ENVIRONMENT') =='DOCKER':
if os.path.exists('config/settings_docker.py'):
print 'Using settings for docker enviroment'
from settings_docker import *
print('Using settings for docker enviroment')
from config.settings_docker import *
else:
if os.path.exists('config/settings_dev.py'):
print 'Using settings for dev enviroment'
from settings_dev import *
print('Using settings for dev enviroment')
from config.settings_dev import *
if os.path.exists('config/settings_testing.py'):
print('Using settings for test enviroment')
from settings_testing import *
from config.settings_testing import *
if os.path.exists('config/settings_live.py'):
print('Using settings for live enviroment')
from settings_live import *
from config.settings_live import *
with web.template as setup:
#css for jquery, material sprite sheet and custom css
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/materialize.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/js/jquery-ui/themes/base/jquery-ui.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-navigation-white.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-action-white.css" media="" type="text/css" />')
@ -65,6 +69,7 @@ with web.template as setup:
setup.persistent_header('<script type="text/javascript" src="/static/js/jquery-2.2.3.min.js"></script>')
setup.persistent_header('<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>')
setup.persistent_header('<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>')
setup.persistent_header('<script type="text/javascript" src="/static/js/materialize.js"></script>')
setup.persistent_header('<script type="text/javascript" src="/static/js/default.js"></script>')
#other favicon etc
@ -75,5 +80,5 @@ with web.template as setup:
domain=domain,
port=port)
db.config(database)
mail.sendmail.set_server(email_server)

View File

@ -1,3 +1,5 @@
import os
import socket
database = {
'charset': 'utf8',
@ -43,8 +45,28 @@ payment_providers = {
google_calendar_id = 'contact@maidstone-hackspace.org.uk'
google_calendar_api_key = 'AIzaSyA98JvRDmplA9lVLZeKwrs1f2k17resLy0'
app_domain = 'http://localhost:5000'
google_captcha = {
'secret': '',
'site': ''
}
# TODO in scaffold remove when commited
def get_ip_from_hostname(hostname, schema='http'):
try:
'%s://%s' % (schema, socket.gethostbyname('nginx'))
except socket.gaierror:
return '%s://%s' % (schema, '127.0.0.1')
app_domain = 'http://%s' % socket.gethostbyname('nginx')
app_email_template_path = 'templates/email/'
schema = 'https:'
domain = get_ip_from_hostname('nginx')
port = ''
rel_uri = '//' + domain
app_domain = 'http:%s' % rel_uri
app_email_template_path = 'templates/email/'
site_name = 'Maidstone Hackspace'
flask_secret_key = '4466ae96-849f-4fbe-a469-3295bf1a13f5'
@ -81,3 +103,11 @@ oauth_conf = {
}
}
email_server = {
'username': '',
'password': '',
'host': 'mail_server',
'port': 1025,
'use_tls': False,
'from': 'support@maidstone-hackspace.org.uk',
'to': 'support@maidstone-hackspace.org.uk'}

View File

@ -3,7 +3,7 @@ page_menu = [
('Home', '/'),
('Chat', '/chat'),
('Donate', '/donate'),
('Contact', '#mailing-list-signup')]
('Contact', '/contact-us')]
nav_for_authenticated_user = (
('Profile', '/profile'),
@ -14,7 +14,8 @@ nav_for_authenticated_user = (
)
banner_images = [
('/static/images/banners/hackspace-banner.png', '', '', ''),
('/static/images/banners/hackspace-banner.png', 'Maidstone Hackspace', 'Maidstone Hackspace', ''),
('/static/images/banners/emf_2016_sign.jpg', 'EMF CAMP 2016', 'EMF CAMP 2016', ''),
('/static/images/banners/audio_board.jpg', 'Audio board', 'Audio board', ''),
('/static/images/banners/microscope.jpg', '', 'Microscope', ''),
('/static/images/banners/object_avoiding_robot.jpg', '', 'Object avoiding robot', ''),
@ -42,6 +43,9 @@ rss_feeds = [{
}, {
'author':'Mike McRoberts',
'url': 'http://thearduinoguy.org/?feed=rss2'
}, {
'author': 'James',
'url': 'https://feeds.feedburner.com/projects-jl'
}]
kent_hackspace = [
@ -58,14 +62,6 @@ maker_events = [
email = 'support@maidstone-hackspace.org.uk'
email_server = {
'user': '',
'password': '',
'host': 'email-smtp.us-east-1.amazonaws.com',
'port': 465,
'from': 'support@maidstone-hackspace.org.uk',
'to': 'support@maidstone-hackspace.org.uk'}
badge_lookup = {
1: 'member',
2: 'backer',

View File

@ -23,7 +23,6 @@ class assign_badge(insert_data):
class fetch_badges(select_data):
#~ debug = True
table = 'badges'
required = {}
columns = {'id', 'name'}
class fetch_badge(select_data):

View File

@ -28,7 +28,6 @@ class get_requests(select_data):
debug = True
#~ limit_rows = False
pagination_rows = 100
required = {}
#~ query_str = 'select id, user_id, name, description, url, price, count(user_id) as quantity from maidstone_hackspace.requests group by name'
query_str = 'select id, user_id, name, description, url, price as quantity from maidstone_hackspace.requests order by name'
columns = {}

View File

@ -9,7 +9,6 @@ query_builder.query_path = os.path.abspath('./data/sql/')
class get_members(select_data):
required = {}
query_file = 'member_list.sql'
columns = {}

View File

@ -76,7 +76,6 @@ class delete_password_reset(delete_data):
"""clean up expired password resets"""
table = 'user_password_reset'
sql_where = 'where DATE_ADD(created, INTERVAL 1 HOUR) < now()'
required = {}
class create_password_reset(insert_data):
@ -89,14 +88,15 @@ class get_user_by_reset_code(select_data):
columns_where = ['reset_code']
class change_password(update_data):
debug=True
table = 'users'
required = {'id', 'password'}
columns_where = ['password']
columns = ['password']
#~ columns_where = ['password']
sql_where = 'id=%(id)s'
class get_users(select_data):
required = {}
query_file = 'get_users.sql'
@ -119,9 +119,9 @@ class get_by_email(select_data):
class get_by_username(select_data):
required = {'email'}
required = {'username'}
query_file = 'get_user_credentials.sql'
columns_where = {'email'}
columns_where = {'username'}
class authorize(select_data):
required = {'id'}
@ -138,6 +138,18 @@ class create_oauth_login(insert_data):
def calculated_data(self):
return {'registered': time.strftime('%Y-%m-%d %H:%M:%S')}
class get_registered_oauth_providers(select_data):
table = 'user_oauth'
columns = {'username', 'provider', 'last_login'}
required = {'user_id'}
query_file = 'get_user_by_oauth_username.sql'
columns_where = {'user_id',}
def calculated_data(self):
return {
'last_login': time.strftime('%Y-%m-%d %H:%M:%S')
}
class update_oauth_login(update_data):
table = 'user_oauth'
columns = {'username', 'provider', 'last_login'}

0
website/data/sql/__init__.py Executable file
View File

54
website/data/sql/badges.py Executable file
View File

@ -0,0 +1,54 @@
import os
import time
from collections import defaultdict
from scaffold.core.data.select import select_data
from scaffold.core.data.insert import insert_data
from scaffold.core.data.update import update_data
from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class create_badge(insert_data):
table = 'badges'
required = {'name'}
columns = {'name'}
class assign_badge(insert_data):
table = 'user_badges'
required = {'user_id', 'badge_id'}
columns = {'user_id', 'badge_id'}
class fetch_badges(select_data):
#~ debug = True
table = 'badges'
columns = {'id', 'name'}
class fetch_badge(select_data):
#~ debug = True
table = 'user_badges'
required = {'user_id'}
columns = {'user_id', 'badge_id'}
columns_where = {'user_id', 'badge_id'}
columns_optional_where = {'user_id', 'badge_id'}
columns_optional = {'user_id', 'badge_id'}
class fetch_user_badges(select_data):
#~ debug = True
table = 'user_badges'
columns = {'user_id', 'badge_id'}
#~ columns_where = {'user_id'}
columns_optional_where = {'user_id', 'badge_id'}
#~ columns_optional = {'user_id', 'badge_id'}
def fetch_user_badges_grouped():
badge_lookup = defaultdict(list)
for badge in fetch_user_badges():
badge_lookup[badge.get('user_id')].append(badge.get('badge_id'))
return badge_lookup
class remove_badge(delete_data):
table = 'user_badges'
required = {'id'}
columns = {'id'}

37
website/data/sql/donate.py Executable file
View File

@ -0,0 +1,37 @@
import os
from scaffold.core.data.select import select_data
from scaffold.core.data.insert import insert_data
#~ from scaffold.core.data.update import update_data
#~ from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class get_pledge(select_data):
debug = True
table = 'pledges'
columns = {'id', 'name', 'total'}
required = {'name'}
class get_pledges(select_data):
debug = True
#~ table = 'pledges'
query_file = 'pledge_totals.sql'
required = {'environment'}
columns_where = {'expired', 'environment'}
grouping = {'name'}
class add_pledge(insert_data):
debug = True
table = 'pledges'
required = {'name'}
columns = {'name'}
class add_payment(insert_data):
debug = True
table = 'pledge_amounts'
required = {'provider_id', 'pledge_id', 'reference', 'amount', 'environment'}
columns = {'provider_id', 'pledge_id', 'reference', 'amount', 'environment'}

43
website/data/sql/equipment.py Executable file
View File

@ -0,0 +1,43 @@
import os
import sys
sys.path.append(os.path.abspath('../../../../scaffold/'))
sys.path.insert(0,os.path.abspath('../../../../scaffold/'))
from scaffold.core.data.select import select_data
from scaffold.core.data.insert import insert_data
from scaffold.core.data.update import update_data
#~ from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class create(insert_data):
table = 'requests'
required = {'user_id', 'name'}
columns = {'user_id', 'name'}
columns_optional = {'price', 'description', 'url'}
class update(update_data):
#~ debug = True
table = 'requests'
required = {'id', 'user_id'}
columns = {'user_id', 'name'}
columns_where = {'id'}
columns_optional = {'price', 'description', 'url'}
class get_requests(select_data):
debug = True
#~ limit_rows = False
pagination_rows = 100
#~ query_str = 'select id, user_id, name, description, url, price, count(user_id) as quantity from maidstone_hackspace.requests group by name'
query_str = 'select id, user_id, name, description, url, price as quantity from maidstone_hackspace.requests order by name'
columns = {}
class get_request(select_data):
table = 'requests'
required = {'id'}
columns = {'*'}
#query_str = 'select id, user_id, name, description, url, price, count(user_id) as quantity from maidstone_hackspace.requests group by name'
columns_where = {'id'}
#columns = {}

0
website/data/sql/fetch_user_badges.sql Normal file → Executable file
View File

0
website/data/sql/get_user_bio.sql Normal file → Executable file
View File

0
website/data/sql/get_user_by_oauth_username.sql Normal file → Executable file
View File

0
website/data/sql/get_user_credentials.sql Normal file → Executable file
View File

0
website/data/sql/get_user_detail.sql Normal file → Executable file
View File

0
website/data/sql/get_user_password_reset.sql Normal file → Executable file
View File

0
website/data/sql/get_users.sql Normal file → Executable file
View File

0
website/data/sql/member_list.sql Normal file → Executable file
View File

35
website/data/sql/members.py Executable file
View File

@ -0,0 +1,35 @@
import os
from scaffold.core.data.select import select_data
#~ from scaffold.core.data.insert import insert_data
from scaffold.core.data.update import update_data
#~ from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class get_members(select_data):
query_file = 'member_list.sql'
columns = {}
class get_member_profile(select_data):
required = {'id'}
query_file = 'get_users.sql'
columns_where = {'id'}
class fetch_member_badges(select_data):
required = {'id'}
query_file = 'fetch_user_badges.sql'
columns_where = {'id'}
class update_membership_status(update_data):
debug = True
query_str = "update `users` set `status`=%(status)s where id=%(user_id)s"
required = {'user_id', 'status'}
columns_where = {}
class fetch_member_subscription(select_data):
debug = True
required = {'user_id'}
query_str = 'select provider_id, subscription_reference from user_membership'
columns_where = {'user_id'}

0
website/data/sql/pledge_totals.sql Normal file → Executable file
View File

28
website/data/sql/profile.py Executable file
View File

@ -0,0 +1,28 @@
import os
from scaffold.core.data.select import select_data
from scaffold.core.data.insert import insert_data
from scaffold.core.data.update import update_data
#~ from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class fetch_users(select_data):
query_file = 'get_users.sql'
class update_description(update_data):
#~ debug = True
table = 'user_detail'
required = {'user_id', 'description', 'skills'}
columns = {'user_id', 'description', 'skills'}
columns_optional = {'description', 'skills'}
columns_where = {'user_id'}
class create_description(insert_data):
#~ debug = True
table = 'user_detail'
required = {'user_id'}
columns = {'user_id'}
columns_optional = {'description', 'skills'}

154
website/data/sql/site_user.py Executable file
View File

@ -0,0 +1,154 @@
import os
import time
from scaffold.core.data.select import select_data
from scaffold.core.data.insert import insert_data
from scaffold.core.data.update import update_data
from scaffold.core.data.delete import delete_data
from scaffold.core.data.sql import query_builder
query_builder.query_path = os.path.abspath('./data/sql/')
class create_basic_user(insert_data):
"""not able to actually log in but registered on the system"""
table = 'users'
required = {'first_name', 'last_name'}
columns = {'first_name', 'last_name'}
def calculated_data(self):
return {'created': time.strftime('%Y-%m-%d %H:%M:%S')}
def set(self, data):
data['created'] = time.strftime('%Y-%m-%d %H:%M:%S')
super(create_basic_user, self).set(data)
class create(insert_data):
table = 'users'
required = {'password', 'username', 'first_name', 'last_name', 'created'}
columns = {'password', 'username', 'first_name', 'last_name', 'created'}
columns_optional = {'profile_image'}
def calculated_data(self):
return {'created': time.strftime('%Y-%m-%d %H:%M:%S')}
def set(self, data):
data['created'] = time.strftime('%Y-%m-%d %H:%M:%S')
super(create, self).set(data)
class update_last_login(update_data):
#~ debug = True
query_str = "update `users` set `last_login`=now()"
required = {'id'}
columns_where = {'id'}
class update_user_email(update_data):
#~ debug = True
query_str = "update `users` set `email`=%(email)s"
required = {'id', 'email'}
columns_where = {'id'}
class update_membership_status(update_data):
#~ debug = True
query_str = "update `users` set `status`=%(status)s where id=%(user_id)s"
required = {'user_id', 'status'}
columns_where = {}
class create_membership(insert_data):
#~ debug = True
table = 'user_membership'
required = {'user_id', 'subscription_reference', 'status', 'amount', 'join_date'}
columns = {'user_id', 'subscription_reference', 'status', 'amount', 'join_date'}
columns_where = {}
class update_membership(update_data):
#~ debug = True
query_str = u"""
update user_membership set
status=%(status)s,
subscription_reference=%(subscription_reference)s,
amount=%(amount)s,
join_date=%(join_date)s
where id=%(user_id)s"""
required = {'subscription_reference', 'status', 'amount', 'join_date'}
columns_where = {}
class delete_password_reset(delete_data):
"""clean up expired password resets"""
table = 'user_password_reset'
sql_where = 'where DATE_ADD(created, INTERVAL 1 HOUR) < now()'
class create_password_reset(insert_data):
table = 'user_password_reset'
required = {'user_id', 'reset_code'}
class get_user_by_reset_code(select_data):
required = {'reset_code'}
query_file = 'get_user_password_reset.sql'
columns_where = ['reset_code']
class change_password(update_data):
table = 'users'
required = {'id', 'password'}
columns_where = ['password']
sql_where = 'id=%(id)s'
class get_users(select_data):
query_file = 'get_users.sql'
class get_user_bio(select_data):
#~ debug = True
required = {'id'}
query_file = 'get_user_bio.sql'
columns_where = {'user_id'}
class get_user_details(select_data):
#~ debug = True
required = {'id'}
query_file = 'get_user_detail.sql'
columns_where = {'users.id'}
class get_by_email(select_data):
required = {'email'}
query_file = 'get_users.sql'
columns_where = {'email'}
class get_by_username(select_data):
required = {'email'}
query_file = 'get_user_credentials.sql'
columns_where = {'email'}
class authorize(select_data):
required = {'id'}
query_file = 'get_user_credentials.sql'
columns_where = {'id'}
class create_oauth_login(insert_data):
#~ debug = True
table = 'user_oauth'
required = {'username', 'provider', 'user_id'}
columns = {'username', 'provider', 'user_id', 'registered'}
def calculated_data(self):
return {'registered': time.strftime('%Y-%m-%d %H:%M:%S')}
class update_oauth_login(update_data):
table = 'user_oauth'
columns = {'username', 'provider', 'last_login'}
required = {'username', 'provider'}
query_file = 'get_user_by_oauth_username.sql'
columns_where = {'username', 'provider'}
def calculated_data(self):
return {
'last_login': time.strftime('%Y-%m-%d %H:%M:%S')
}
class fetch_oauth_login(select_data):
required = {'username', 'provider'}
query_file = 'get_user_by_oauth_username.sql'
columns_where = {'username', 'provider'}

View File

@ -3,9 +3,6 @@ import sys
import codecs
import argparse
sys.path.append(os.path.abspath('../../../scaffold/'))
sys.path.insert(0,os.path.abspath('../../../scaffold/'))
from scaffold import web
web.load_widgets('widgets')
@ -33,7 +30,7 @@ def generate_rss():
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Generate static pages')
parser.add_argument('--folder', dest='folder', default='./html/' ,nargs='?', help='output folder')
parser.add_argument('--folder', dest='folder', default='./static/html/' ,nargs='?', help='output folder')
#module, function, output file
pages_list = (
@ -44,7 +41,6 @@ if __name__ == "__main__":
('pages.competition', 'index', 'competition.htm'))
args = parser.parse_args()
print args.folder
for module, page, filename in pages_list:
page_module = __import__(module, globals(), locals(), page)
@ -56,5 +52,5 @@ if __name__ == "__main__":
print('Failed to Generate %s%s' % (args.folder, filename))
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_tb(exc_traceback, limit=5, file=sys.stdout)
traceback.print_tb(exc_traceback, limit=10, file=sys.stdout)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,6 +12,7 @@ from pages import homepage
from pages import chat
from pages import blog
from pages import members
from pages.contact import contact_page, submit_contact_page
from pages.core.login_pages import login_pages
from pages.core.authorize import authorize_pages, login_manager
@ -21,7 +22,6 @@ from pages.equipment import equipment_pages
from pages.profile import profile_pages
web_app = Flask(__name__, static_folder='static')
web_app.config['PROPAGATE_EXCEPTIONS'] = True
web_app.secret_key = settings.flask_secret_key
@ -73,5 +73,15 @@ def chat_index():
"""competition page"""
return make_response(chat.index())
@web_app.route("/contact-us/", methods=['GET'])
def contact_us():
"""Contact page"""
return make_response(contact_page())
@web_app.route("/contact-us/", methods=['POST'])
def submit_contact_us():
"""Contact page"""
return make_response(submit_contact_page())
if __name__ == '__main__':
web_app.run(host='0.0.0.0', port=5000, debug=True)

View File

@ -0,0 +1,28 @@
from uuid import uuid4
import os
import hashlib
import requests
def save_remote_image(url, path='', domain='', skip_exists=True):
filename = '%s.%s' % (hashlib.md5(url.encode()).hexdigest(), url[-3:])
filepath = os.path.abspath('./static/images/blogs/%s' %(filename))
urlpath = 'static/images/blogs/' + filename
if not url:
return None
if url[-3:] not in ('jpg', 'png'):
return None
print(domain + urlpath)
if skip_exists is True and os.path.exists(filepath):
return domain + urlpath
r = requests.get(url, stream=True)
if r.status_code != 200:
return None
with open(filepath, 'wb') as f:
for chunk in r.iter_content(1024):
f.write(chunk)
return domain + urlpath

View File

@ -1,15 +1,15 @@
from mailer import Mailer
from mailer import Message
from config.logger import log
class sendmail:
host = 'localhost'
config = 'localhost'
charset = 'utf-8'
subject_prefix = ''
@classmethod
def set_server(cls, host='localhost', charset='utf-8'):
cls.host = host
def set_server(cls, config, charset='utf-8'):
cls.config = config
def __call__(self, **args):
return self
@ -19,20 +19,35 @@ class sendmail:
self.body = fp.read()
self.body.format(**params)
def send(self, from_address, to_address, subject, body=None, html=True):
message = Message(
From=from_address,
To=to_address,
charset=self.charset
)
try:
message = Message(
From=from_address,
To=to_address,
charset=self.charset
)
if body:
if body is None:
body = ''
self.body = body
message.Subject = "%sAn HTML Email" % self.subject_prefix
message.Html = self.body
message.Body = self.body
message.Subject = "%s - %s" % (self.subject_prefix, subject)
message.Html = self.body
message.Body = self.body
except Exception as e:
log.exception('[scaffold_mailer] - Failed to create message object for mailer')
return False
sender = Mailer(self.host)
sender.send(message)
try:
sender = Mailer(
host=self.config.get('host'),
port=self.config.get('port'),
use_tls=self.config.get('use_tls', False),
use_ssl=True,
usr=self.config.get('username'),
pwd=self.config.get('password'))
sender.send(message)
except Exception as e:
log.exception('[scaffold_mailer] - Failed to connect to smtp sever and send message with subject: %s' % message.Subject)
return False
return True

View File

@ -24,8 +24,8 @@ class payment:
self.provider_id = PROVIDER_ID.get(provider)
if provider == 'paypal':
print settings.payment_providers[provider]['credentials']
paypal.configure(**settings.payment_providers[provider]['credentials'])
print(settings.payment_providers[provider]['credentials'])
return
#~ environment = int('production' = settings.payment_providers[provider]['environment'])
@ -52,13 +52,13 @@ class payment:
"description": reference}]})
payment_response = payment.create()
print 'payment create'
print('payment create')
if payment_response:
print payment_response
print(payment_response)
for link in payment.links:
if link.method == "REDIRECT":
redirect_url = str(link.href)
print redirect_url
print(redirect_url)
return str(redirect_url)
else:
print("Error while creating payment:")
@ -84,17 +84,18 @@ class payment:
'amount': paying_member.amount}
if self.provider == 'paypal':
#~ I-S39170DK26AF
#~ start_date, end_date = "2014-07-01", "2014-07-20"
billing_agreement = paypal.BillingAgreement.find('')
print billing_agreement
print dir(billing_agreement)
print(billing_agreement)
print(dir(billing_agreement))
#~ print billing_agreement.search_transactions(start_date, end_date)
#~ transactions = billing_agreement.search_transactions(start_date, end_date)
payment_history = paypal.Payment.all({"count": 2})
# List Payments
print("List Payment:")
print payment_history
print(payment_history)
for payment in payment_history.payments:
print(" -> Payment[%s]" % (payment.id))
#~ print paypal.BillingAgreement.all()
@ -104,8 +105,8 @@ class payment:
print("List BillingPlan:")
for plan in history.plans:
print dir(plan)
print plan.to_dict()
print(dir(plan))
print(plan.to_dict())
print(" -> BillingPlan[%s]" % (plan.id))
#~ merchant = gocardless.client.merchant()
@ -128,12 +129,12 @@ class payment:
}
if self.provider == 'paypal':
print 'subscribe_confirm'
print('subscribe_confirm')
payment_token = args.get('token', '')
billing_agreement_response = paypal.BillingAgreement.execute(payment_token)
amount = 0
print billing_agreement_response
print billing_agreement_response.id
print(billing_agreement_response)
print(billing_agreement_response.id)
for row in billing_agreement_response.plan.payment_definitions:
amount = row.amount.value
@ -147,16 +148,16 @@ class payment:
def unsubscribe(self, reference):
if self.provider == 'gocardless':
print 'unsubscribe gocardless'
print('unsubscribe gocardless')
subscription = gocardless.client.subscription(reference)
print subscription.cancel()
print(subscription.cancel())
if self.provider == 'paypal':
# this may be wrong
# ManageRecurringPaymentsProfileStatus
print reference
print(reference)
billing_plan = paypal.BillingAgreement.find(reference)
print billing_plan
print(billing_plan)
print(billing_plan.error)
#~ billing_plan.replace([{"op": "replace","path": "/","value": {"state":"DELETED"}}])
print(billing_plan.error)
@ -212,7 +213,7 @@ class payment:
],
"type": "INFINITE"
})
print 'create bill'
print('create bill')
response = billing_plan.create()
@ -229,8 +230,8 @@ class payment:
})
if billing_agreement.create():
print 'billing agreement id'
print billing_agreement.id
print('billing agreement id')
print(billing_agreement.id)
for link in billing_agreement.links:
if link.rel == "approval_url":
@ -238,24 +239,24 @@ class payment:
return approval_url
else:
print(billing_agreement.error)
print 'failed'
print('failed')
def confirm(self, args):
confirm_details = {}
confirm_details['successfull'] = False
print '---------------------'
print args
print('---------------------')
print(args)
from pprint import pprint
if self.provider == 'paypal':
print args.get('paymentId')
print args.get('PayerID')
print(args.get('paymentId'))
print(args.get('PayerID'))
payment = paypal.Payment.find(args.get('paymentId'))
pprint(payment)
print pprint(payment)
print payment
print(pprint(payment))
print(payment)
confirm_details['name'] = payment['payer']['payer_info'].first_name + ' ' + payment['payer']['payer_info'].last_name
confirm_details['user'] = payment['payer']['payer_info'].email

18
website/libs/recapture.py Normal file
View File

@ -0,0 +1,18 @@
"""https://developers.google.com/recaptcha/docs/verify"""
from requests import post
from config.logger import log
def verify_captcha(secret, response, remoteip=''):
try:
response = post(
'https://www.google.com/recaptcha/api/siteverify',
{'secret': secret,
'response': response,
'remoteip': remoteip})
json = response.json()
except:
log.error('Failed to get capture json response from google')
return False
return json.get('success')

View File

@ -7,8 +7,8 @@ from scaffold.core.data.database import db
db.config(settings.database)
from scaffold.core.data.migrations import export_schema, import_schema
export_schema(os.path.abspath('./data/migrate/'))
#~ import_schema(os.path.abspath('./data/migrate/'))
#export_schema(os.path.abspath('./data/migrate/'))
import_schema(os.path.abspath('./data/migrate/'))

View File

@ -15,15 +15,15 @@ web.template.append('<link rel="icon" type="image/png" href="/static/images/icon
#paths
web.document_root = os.path.abspath('./')
web.template.domain = 'http://maidstone-hackspace.org.uk/'
web.template.domain = 'https://maidstone-hackspace.org.uk/'
web.template.theme_full_path = os.path.abspath('./static') + os.sep
domain = 'http://192.168.21.41:5000/'
image_path = domain + os.sep + 'images' + os.sep
#~ domain = 'http://192.168.21.41:5000/'
#~ image_path = domain + os.sep + 'images' + os.sep
with web.template as setup:
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/materialize.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />')
#~ setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/js/jquery-ui/themes/base/jquery-ui.css" media="" type="text/css" />')
#setup.persistent_header('<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.css">')
#setup.persistent_header('<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=RobotoDraft:300,400,500,700,400italic">')
@ -31,10 +31,10 @@ with web.template as setup:
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-action-white.css" media="" type="text/css" />')
setup.persistent_header('<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-content-white.css" media="" type="text/css" />')
setup.persistent_header('<script type="text/javascript" src="/static/js/jquery-2.2.3.min.js"></script>')
setup.persistent_header('<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>')
setup.persistent_header('<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>')
setup.persistent_header('<script type="text/javascript" src="/static/js/materialize.js"></script>')
setup.persistent_header('<script type="text/javascript" src="/static/js/default.js"></script>')
#setup.persistent_header('<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-aria.min.js"></script>')
@ -50,18 +50,19 @@ def header(title, description='Maidstone Hackspace is a shared space where artis
web.template.body.append(web.header_strip.render())
# top menu bar navigation
web.menu.create('/' + url).set_id('leftNav')
web.menu.create('/' + url).set_classes('col s10 offset-s1')
web.menu * site.page_menu
web.menu.append('Group', '/mailing-list')
if current_user and current_user.is_authenticated():
if current_user and current_user.is_authenticated:
web.menu.append('Logout', '/logout')
web.navigation_bar.create(hide=(False if url=='/profile' else True))
web.navigation_bar * site.nav_for_authenticated_user
web.template.body.append(web.navigation_bar.render())
else:
web.menu.append('Login', '/login')
web.template.body.append(web.menu.render())
web.template.body.append(web.container.create(web.menu.render()).set_id('menubar').set_classes('row').render())
# lets create the footer
web.footer_content.create().append(

View File

@ -12,5 +12,5 @@ def index():
web.page.create(web.title.create('IRC Chat Room').render())
web.page.create(web.paragraph.create('Pop in and say hi, please be patient users tend to idle and will respond when they get a chance.').render())
web.page.section(web.chat.create('maidstone-hackspace').render())
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return footer()

View File

@ -8,5 +8,5 @@ def index():
web.page.create(web.title.create('IRC Chat Room').render())
web.page.create(web.paragraph.create('Pop in and say hi, please be patient users tend to idle, but will likely respond given a chance.').render())
web.page.section(web.chat.create('maidstone-hackspace').render())
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return footer()

56
website/pages/contact.py Normal file
View File

@ -0,0 +1,56 @@
from pages import web
from pages import header, footer
from config.settings import google_captcha, email_server
from libs.mail import sendmail
from flask import get_flashed_messages, flash, request
from libs.recapture import verify_captcha
def contact_page():
web.template.create('Maidstone Hackspace - Chat room')
header('Maidstone Hackspace Chat')
web.contact_form.capture_settings = google_captcha
web.contact_form.create('Contact Us')
web.contact_form.enable_capture()
web.contact_form.render()
web.simple_form.create()
web.simple_form.append(input_type='text', input_name='test', label='my label')
web.page.create(web.title.create('Contact Form').render())
web.page.section(web.contact_form.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return footer()
def submit_contact_page():
subject = '[%s] - %s' % (
request.form.get('form_query', 'MHS'),
request.form.get('form_subject', 'No Subject ?')
)
# Check user password the robot check
print(request.form.get('g-recaptcha-response', ''))
print(google_captcha.get('secret'))
print(request.remote_addr)
success = verify_captcha(
secret=google_captcha.get('secret'),
response=request.form.get('g-recaptcha-response', ''),
remoteip=request.remote_addr)
if success is False:
flash('Message failed to send, capture failed to validate are you a robot ?')
return contact_page()
# Send Email and let user know if it worked or not
success = sendmail().send(
from_address=request.form.get('email'),
to_address='contact@maidstone-hackspace.org.uk',
subject=subject,
body=request.form.get('form_message'))
if success is False:
flash('Sorry system was unable to send your message, someone has been notified.')
return contact_page()
flash('Your message has been sent, we will get back to you shortly.')
return contact_page()

View File

@ -27,7 +27,8 @@ authorize_pages = Blueprint('authorize_pages', __name__, template_folder='templa
login_manager = LoginManager()
login_manager.login_view = '/login'
oauth_lookup = {'google':1, 'github':2, 'facebook':3}
oauth_lookup_id = {'google':1, 'github':2, 'facebook':3}
oauth_lookup_name = dict((v, k) for k, v in oauth_lookup_id.items())
def is_weak_password(password1, password2):
@ -36,32 +37,28 @@ def is_weak_password(password1, password2):
return True
# TODO check length and chars
password1 = password2 = None
return False
def todict(data):
new_dict = {}
for key, value in data.items():
new_dict[key] = value
return new_dict
#~ def todict(data):
#~ new_dict = {}
#~ for key, value in data.items():
#~ new_dict[key] = value
#~ return new_dict
class User(UserMixin):
def __init__(self, user_id, active=True):
print user_id
self.id = None
user_details = site_user.get_user_details({'id': user_id}).get()
self.active = False
print 'user'
print user_details
if user_details:
self.active = True
#~ self.check_password(user_details.get('password'))
self.id = user_id
self.name = user_details.get('username')
print self.name
self.active = active
#~ self.is_authenticated = self.active
def get_id(self):
return self.id
@ -90,8 +87,6 @@ def load_token(request):
if token is not None:
username, password = token.split(":") # naive token
print username
print password
user_entry = User.get(username)
if (user_entry is not None):
user = User(user_entry[0], user_entry[1])
@ -144,7 +139,7 @@ def register_submit():
new_user.execute(data)
flash('Your account has now been created')
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return make_response(footer())
@authorize_pages.route("/oauth/<provider>/<start_oauth_login>/", methods=['GET'])
@ -157,17 +152,17 @@ def oauth(provider, start_oauth_login=False):
oauth_access_type = ''
oauth_approval_prompt = ''
if oauth_live is False:
print('offline testing')
oauth_verify = False
oauth_access_type = 'offline'
oauth_approval_prompt = "force"
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
if start_oauth_login:
print oauth_provider.get('redirect_uri')
oauth_session = OAuth2Session(
oauth_provider.get('client_id'),
scope=oauth_provider.get('scope'),
redirect_uri=oauth_provider.get('redirect_uri'))
redirect_uri=request.url_root + oauth_provider.get('redirect_uri'))
if provider == 'facebook':
oauth_session = facebook_compliance_fix(oauth_session)
@ -183,15 +178,15 @@ def oauth(provider, start_oauth_login=False):
session.modified = True
return redirect(authorization_url)
if session.get('oauth_state', None) is None:
flash('Something went wrong, oauth session not started')
return redirect('/login')
# allready authorised so lets handle the callback
oauth_session = OAuth2Session(
oauth_provider.get('client_id'),
state=session['oauth_state'],
redirect_uri=oauth_provider.get('redirect_uri'))
print '----------'
print oauth_provider.get('redirect_uri')
print request.url
redirect_uri=request.url_root + oauth_provider.get('redirect_uri'))
if provider == 'facebook':
oauth_session = facebook_compliance_fix(oauth_session)
@ -208,11 +203,8 @@ def oauth(provider, start_oauth_login=False):
response = oauth_session.get(oauth_provider.get('user_uri'))
oauth_response = response.json()
print 'oauth response'
print oauth_response
oauth_id = oauth_response.get('login') or oauth_response.get('id')
provider_id = oauth_lookup.get(provider)
provider_id = oauth_lookup_id.get(provider)
oauth_user = site_user.fetch_oauth_login({
'username': oauth_id or '',
'provider': provider_id
@ -233,8 +225,6 @@ def oauth(provider, start_oauth_login=False):
flash('Your new profile has been created, and your now logged in')
print 'current user'
print current_user.get_id()
if current_user.get_id():
# link oauth to users account
site_user.create_oauth_login().execute({
@ -243,9 +233,6 @@ def oauth(provider, start_oauth_login=False):
'provider': provider_id})
return redirect('/profile')
print oauth_response
print '-----'
print oauth_response.get('email') or ''
# create new user from oauth information
new_user_details = {
@ -278,13 +265,11 @@ def oauth(provider, start_oauth_login=False):
@authorize_pages.route("/change-password", methods=['GET'])
def change_password(code=None):
#if we have a code this is a password reset, so try and login the user first
print code
site_user.delete_password_reset().execute({})
if code:
user_details = site_user.get_user_by_reset_code({'reset_code': code}).get()
print user_details
if not user_details:
#invalid code so pretend the page does not even exist
return abort(404)
@ -292,7 +277,6 @@ def change_password(code=None):
#datetime.datetime.now() + datetime.timedelta(minutes=15)
has_date_expired = user_details.get('created') + datetime.timedelta(minutes=60)
if has_date_expired < datetime.datetime.now():
print 'date expired'
#date expired so clean up and pretend the page does not exist
return abort(404)
#challenge passed so login the user so they can change there password
@ -307,7 +291,7 @@ def change_password(code=None):
web.page.section(
web.change_password_box.create().render()
)
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return make_response(footer())
@login_required
@ -315,16 +299,16 @@ def change_password(code=None):
def change_password_submit(code=None):
if not session.get('user_id'):
abort(404)
user_details = site_user.authorize({
'id': session.get('user_id')}).get()
if is_weak_password(request.form.get('password'), request.form.get('password_confirm')):
print 'password not strong enough'
redirect('/login')
pw_hash = generate_password_hash(request.form.get('password'))
site_user.change_password().execute({'id': user_details.get('user_id'), 'password': pw_hash})
user_details = site_user.authorize({
'id': session.get('user_id')}).get()
site_user.change_password().execute({
'id': user_details.get('user_id'),
'password': pw_hash})
web.template.create('Maidstone Hackspace - Profile')
header('User Profile')
@ -381,18 +365,6 @@ def reset_password_submit():
web.template.body.append(web.page.render())
return make_response(footer())
#~ @authorize_pages.route("/login", methods=['GET'])
#~ def login_screen():
#~ web.template.create('Maidstone Hackspace - Login')
#~ header('Members Login')
#~ web.page.create('Member Login')
#~ web.page.section(
#~ web.login_box.create().enable_oauth('google').enable_oauth('facebook').enable_oauth('github').render()
#~ )
#~ web.template.body.append(web.page.render())
#~ return make_response(footer())
@authorize_pages.route("/login/failure", methods=['GET'])
def login_Failure():
web.template.create('%s - Login' % site_name)

View File

@ -1,5 +1,6 @@
import os
from werkzeug.security import generate_password_hash, check_password_hash
from flask import session, flash
from flask import redirect, abort
from flask import make_response
@ -12,6 +13,7 @@ from requests_oauthlib.compliance_fixes import facebook_compliance_fix
from scaffold import web
from libs.mail import sendmail
from pages import header, footer
from pages.core.authorize import User
from data import site_user
from config.settings import *
from constants import *
@ -26,9 +28,9 @@ def login_screen():
header('Members Login')
web.page.create('Member Login')
web.page.section(
web.login_box.create().enable_oauth('google').enable_oauth('facebook').enable_oauth('github').render()
web.loginBox.create().enable_oauth('google').enable_oauth('facebook').enable_oauth('github').render()
)
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return make_response(footer())
@ -37,7 +39,7 @@ def login_screen_submit():
"""handle the login form submit"""
# try to find user by username
user_details = site_user.get_by_username({
'email': request.form.get('username')}).get()
'username': request.form.get('username')}).get()
# not found so lets bail to the login screen
if not user_details:
@ -56,7 +58,7 @@ def login_screen_submit():
)
flash('You have successfully logged in !')
site_user.update_last_login().execute(user_details)
site_user.update_last_login().execute({'id': user_details.get('user_id')})
# logged in but no E-Mail so lets ask the user for there email.
if not user_details.get('email'):

View File

@ -40,7 +40,7 @@ def index():
web.form.append(name='amount', label='Donation Amount', placeholder='50.00', value='50.00')
web.page.append(web.form.render())
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return web.render()
@ -67,10 +67,8 @@ def populate_by_name():
web.template.body.append('Populating users')
user_list = {}
#make sure we have all users in the system
print '--------------'
#~ users_emails = []
for user in merchant.users():
#~ print dir(user)
user_list[user.id] = user.email
#~ users_emails.append(user.email)
site_user.create_basic_user().execute({

View File

@ -11,3 +11,29 @@ def twitter():
web.twitter_feed.render())
web.template.body.append(web.page.render())
return footer()
# normally you will abstract the html into the widgets folder so its reusable
# to keep things as simple as possibler for everyone you can bypass and render you html direct
# either to tha page web.page.section or to web.template.body
# This is the simplest way to make a page
def simple_page():
web.template.create('Maidstone Hackspace')
header('Maidstone Hackspace Homepage')
# render to a page in this way
web.page.create('Page title ')
web.page.section('<p>Page Body<p>')
web.template.body.append(web.page.render())
# render direct to the template body in this way
data = {
'first_value': 'value from where ever',
'second_value': 'value from where ever'}
web.template.body.append("""
<div>some content here</div>
<p>paragrph or any other html you want to place in here</p>
<span>{first_value}</span>
<span>{second_value}</span>
""".format(*data))
return footer()

View File

@ -19,6 +19,6 @@ def index(request_id=None):
web.container.create(web.google_groups.render()).set_classes('margin_default')
web.page.append(web.container.render())
web.template.body.append(web.page.render())
web.template.body.append(web.page.set_classes('page col s10 offset-s1').render())
return footer()

View File

@ -1,19 +1,16 @@
import constants as site
#~ from config.settings import *
from config.settings import google_calendar_id, google_calendar_api_key
from libs.image_fetcher import save_remote_image
from config.settings import google_calendar_id, google_calendar_api_key, app_domain
from scaffold.readers.rss_reader import feed_reader
#~ from libs.rss_fetcher import feed_reader
from scaffold import web
#~ from pages import web
from pages import header, footer
def index():
web.template.create('Maidstone Hackspace')
header('Maidstone Hackspace Homepage')
web.page.create('')
web.page.create('').set_classes('page col s10 offset-s1')
web.page.section(
web.div.create(
web.google_calendar.create(
@ -53,18 +50,22 @@ def index():
# fetch the rss feeds from the various blogs for the homepage
web.columns.create()
feed = feed_reader(site.rss_feeds)
web.tiles.create()
for row in feed:
web.tiles.create()
web.columns.append(
web.tiles.append(
row['image'] = save_remote_image(row.get('image'), domain=app_domain + '/')
web.tiles.append(
title = row.get('title'),
author = row.get('author'),
link = row.get('url'),
image = row.get('image'),
date = row.get('date'),
description = row.get('description')).render())
web.page.append(web.columns.render())
description = row.get('description')).render()
#~ web.columns.append(
#~ )
web.page.append(web.div.create(web.tiles.render()).set_classes('row').render())
web.template.body.append(web.page.render())
return footer()

View File

@ -35,9 +35,9 @@ def index():
if item.get('status') is 1:
count_members += 1
web.info_box.create('Current Users')
web.info_box.append('Members %d<br />' % count_members)
web.info_box.append('Users %d<br />' % count_users)
web.info_box.create('<div class="col s4 dark-blue">Current Users</div>').set_classes('row')
web.info_box.append('<div class="col s4 dark-blue">Members %d</div>' % count_members)
web.info_box.append('<div class="col s4 dark-blue">Users %d</div>' % count_users)
web.page.section(web.info_box.render())
web.container.create(web.member_tiles.render()).set_classes('members')

View File

@ -5,9 +5,10 @@ from flask.ext.login import current_user, login_required
from constants import badge_lookup
from pages.core.authorize import oauth_lookup_name
from pages import web
from pages import header, footer
from data.site_user import get_user_details, update_membership, update_membership_status, get_user_bio, create_membership
from data.site_user import get_user_details, get_registered_oauth_providers, update_membership, update_membership_status, get_user_bio, create_membership
from data.profile import update_description, create_description, fetch_users
from data import badges
from data import members
@ -23,32 +24,24 @@ profile_pages = Blueprint('profile_pages', __name__, template_folder='templates'
def index():
web.template.create('Maidstone Hackspace - User profile')
header('User Profile', url='/profile')
print current_user
user = get_user_details({'id': current_user.get_id()}).get()
user_oauth_providers = [provider for provider in get_registered_oauth_providers({'user_id': current_user.get_id()})]
name = '%s %s' % (user.get('first_name', '').capitalize(), user.get('last_name', '').capitalize())
name = '%s %s' % (
user.get('first_name', '').capitalize(),
user.get('last_name', '').capitalize())
web.page.create('%s - Profile' % name)
web.columns.create()
web.paragraph.create(
web.images.create(user.get('profile_image', '/static/images/hackspace.png'), name).add_attributes('width', '200').render()
)
web.paragraph.add(name)
web.paragraph.add('%s' % (user.get('email')))
web.paragraph.add('%s' % (user.get('email', '') if user.get('email', '') else ''))
web.paragraph.add('Last Login %s' % (user.get('last_login', '')))
web.paragraph.add('Member since %s' % (user.get('created', '')))
web.paragraph.add('Description %s' % (user.get('description', '')))
web.paragraph.add('Skills %s' % (user.get('skills', '')))
web.columns.append(web.paragraph.render())
# membership form
web.columns.append(
web.member_card.create(
reference=str(user.get('user_id')).zfill(5),
name=name,
active=user.get('status')==1
).render()
)
web.div.create(web.paragraph.render())
web.paragraph.create(
web.link.create(
@ -63,11 +56,33 @@ def index():
'Link login provider',
'/login'
).render())
web.table.create('', ('Login providers', 'Last login'))
for provider in user_oauth_providers:
web.table.append((
str(oauth_lookup_name.get(int(provider.get('provider')))),
provider.get('last_login') if provider.get('last_login') else 'Unknown'))
web.paragraph.append(
web.table.render())
web.columns.append(web.paragraph.render())
web.page.section(
web.div.append(
web.paragraph.render()
).set_classes('col s6').render()
)
# membership form
web.page.append(
web.div.create(
web.member_card.create(
reference=str(user.get('user_id')).zfill(5),
name=name,
active=user.get('status')==1
).render()
).set_classes('col s6').render()
)
web.page.section(web.columns.render())
web.template.body.append(web.page.render())
web.template.body.append(web.popup.create('').render())
@ -83,26 +98,24 @@ def setup():
badges.create_badge().execute({'id': badge_id, 'name': badge_name})
user_lookup = {}
for member in fetch_users():
for member in fetch_users():
user_lookup[member.get('email')] = member.get('user_id')
provider = payment(provider='paypal', style='payment')
for item in provider.fetch_subscriptions():
print item
print(item)
print user_lookup
merchant = gocardless.client.merchant()
#https://jsfiddle.net/api/post/library/pure/
for paying_member in merchant.subscriptions():
print dir(paying_member)
print paying_member.user()
print paying_member.amount
print(dir(paying_member))
print(paying_member.user())
print(paying_member.amount)
user=paying_member.user()
print '---------------'
print user.email
print(user.email)
user_id = user_lookup.get(user.email)
print user_id
print(user_id)
update_membership_status().execute({'user_id': user_id, 'status': '1'})
create_membership().execute({'user_id': user_id, 'status': '1', 'join_date': paying_member.created_at, 'amount': paying_member.amount, 'subscription_id': paying_member.id})
@ -138,8 +151,8 @@ def cancel_membership():
user_code = str(user.get('user_id')).zfill(5)
subscription = members.fetch_member_subscription({'user_id': current_user.get_id()}).get()
print subscription.get('provider_id')
print subscription.get('subscription_reference')
print(subscription.get('provider_id'))
print(subscription.get('subscription_reference'))
provider = payment(provider='paypal', style='payment')
@ -194,10 +207,10 @@ def membership_signup(provider):
def update_profiles():
"""this is used to sync up older accounts"""
for user in get_users():
print user
print(user)
for payment in get_users():
print user
print(user)
return web.form.render()
@ -205,9 +218,8 @@ def update_profiles():
@login_required
def edit_profile():
user_details = get_user_details({'id': current_user.get_id()}).get() or {}
print user_details
if not user_details:
print 'create'
print('create')
create_description().execute({'user_id': current_user.get_id()})
web.form.create('Update your details', '/profile/update')
web.form.append(name='description', label='Description', placeholder='This is me i am great', value=user_details.get('description') or '')

0
website/setup.py Executable file → Normal file
View File

275
website/static/css/default.css Normal file → Executable file

File diff suppressed because one or more lines are too long

0
website/static/css/materialize.css vendored Normal file → Executable file
View File

0
website/static/css/sprite-action-white.css Normal file → Executable file
View File

0
website/static/css/sprite-content-white.css Normal file → Executable file
View File

0
website/static/css/sprite-navigation-white.css Normal file → Executable file
View File

0
website/html/404.htm → website/static/html/404.htm Normal file → Executable file
View File

123
website/static/html/blog.htm Executable file

File diff suppressed because one or more lines are too long

78
website/html/chat.htm → website/static/html/chat.htm Normal file → Executable file
View File

@ -2,45 +2,47 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:sa="/">
<head>
<link rel="stylesheet" id="navigationCss" href="/static/css/materialize.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/js/jquery-ui/themes/base/jquery-ui.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-navigation-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-action-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-content-white.css" media="" type="text/css" />
<script type="text/javascript" src="/static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/static/js/jquery-2.2.3.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>
<script type="text/javascript" src="/static/js/materialize.js"></script>
<script type="text/javascript" src="/static/js/default.js"></script>
<link rel="icon" type="image/png" href="/static/images/favicon.png">
<title>Maidstone Hackspace - Chat room</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="headerstrip"><nav class="navstrip"><div class="left"><a id="mini_logo" href="/login"><img src="//127.0.0.1:5000/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="social"><div class="btn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="http://maidstone-hackspace.org.uk/">Tweet</a></div><div class="btn"><div class="fb-share-button" data-href="http://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="btn"><script type="IN/Share" data-url="http://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="btn"><div size="standard" class="g-plusone" data-href="http://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<nav id="leftNav" class="menu" >
<div id="headerstrip" class="row"><nav class="navstrip"><div class="navstripleft col s6"><a id="mini_logo" href="/login"><img src="//http://127.0.0.1/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="col s6 offset-s8 social"><div class="socbtn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="https://maidstone-hackspace.org.uk/" data-hashtags="mhackspace">Tweet</a></div><div class="socbtn"><div class="fb-share-button" data-href="https://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="socbtn"><script type="IN/Share" data-url="https://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="socbtn"><div size="standard" class="g-plusone" data-href="https://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<div id="menubar" class="row" ><nav class="col s10 offset-s1" >
<ul>
<li class="active mi0"><a href="/" >Home</a></li>
<li class="mi1"><a href="/chat" >Chat</a></li>
<li class="mi2"><a href="/donate" >Donate</a></li>
<li class="mi3"><a href="#mailing-list-signup" >Contact</a></li>
<li class="mi4"><a href="/login" >login</a></li>
<li class="mi3"><a href="/contact-us" >Contact</a></li>
<li class="mi4"><a href="/mailing-list" >Group</a></li>
<li class="mi5"><a href="/login" >Login</a></li>
</ul>
<div style="clear:both;"></div>
</nav>
<div class="page" >
</nav></div>
<div class="row"><div class="page col s10 offset-s1" >
<header class="pageHeader">
<p>Pop in and say hi, please be patient users tend to idle, but will likely respond given a chance.</p></header>
<section class="pageSection">
<section class="pageSection col s12">
<div class="social-chat"><div class="contain"><iframe src="https://webchat.freenode.net?channels=%23maidstone-hackspace&uio=MTE9MjU207"></iframe></div></div></section>
<footer class="pageFooter">
<footer class="pageFooter col s12">
</footer>
</div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="http://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">Browse Archives</a></form><div style="clear:both;"></div><div></div></div><div>
</div></div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="https://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">View Group</a></form><div style="clear:both;"></div><div></div></div><div>
<!--google analytics-->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<script><!--//--><![CDATA[//><!--!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'http://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
//]]></script>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
<script src="//platform.linkedin.com/in.js" type="text/javascript"> lang: en_US</script>
@ -48,29 +50,6 @@
//facebook share
(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.3";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));
//]]></script><script type="text/javascript" ><!--//--><![CDATA[//><!--
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
var app = angular.module('myApp', ['ngAnimate']);
app.controller('sliderController', function($scope, $interval) {
@ -113,6 +92,29 @@ app.controller('sliderController', function($scope, $interval) {
});
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
//]]>
</script>

View File

@ -2,49 +2,52 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:sa="/">
<head>
<link rel="stylesheet" id="navigationCss" href="/static/css/materialize.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/js/jquery-ui/themes/base/jquery-ui.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-navigation-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-action-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-content-white.css" media="" type="text/css" />
<script type="text/javascript" src="/static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/static/js/jquery-2.2.3.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>
<script type="text/javascript" src="/static/js/materialize.js"></script>
<script type="text/javascript" src="/static/js/default.js"></script>
<link rel="icon" type="image/png" href="/static/images/favicon.png">
<title>Maidstone Hackspace - Screw sorting competition</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="headerstrip"><nav class="navstrip"><div class="left"><a id="mini_logo" href="/login"><img src="//127.0.0.1:5000/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="social"><div class="btn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="http://maidstone-hackspace.org.uk/">Tweet</a></div><div class="btn"><div class="fb-share-button" data-href="http://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="btn"><script type="IN/Share" data-url="http://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="btn"><div size="standard" class="g-plusone" data-href="http://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<nav id="leftNav" class="menu" >
<div id="headerstrip" class="row"><nav class="navstrip"><div class="navstripleft col s6"><a id="mini_logo" href="/login"><img src="//http://127.0.0.1/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="col s6 offset-s8 social"><div class="socbtn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="https://maidstone-hackspace.org.uk/" data-hashtags="mhackspace">Tweet</a></div><div class="socbtn"><div class="fb-share-button" data-href="https://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="socbtn"><script type="IN/Share" data-url="https://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="socbtn"><div size="standard" class="g-plusone" data-href="https://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<div id="menubar" class="row" ><nav class="col s10 offset-s1" >
<ul>
<li class="active mi0"><a href="/" >Home</a></li>
<li class="mi1"><a href="/chat" >Chat</a></li>
<li class="mi2"><a href="/donate" >Donate</a></li>
<li class="mi3"><a href="#mailing-list-signup" >Contact</a></li>
<li class="mi4"><a href="/login" >login</a></li>
<li class="mi3"><a href="/contact-us" >Contact</a></li>
<li class="mi4"><a href="/mailing-list" >Group</a></li>
<li class="mi5"><a href="/login" >Login</a></li>
</ul>
<div style="clear:both;"></div>
</nav>
<div class="page" >
</nav></div>
<div class="row"><div class="page col s10 offset-s1" >
<header class="pageHeader">
<img src="/static/images/competitions/screw_sorting_competition_banner.jpg" alt="Screw sorting competition banner" align="middle" style="margin:auto;display:block;width:500px;" />
</header>
<section class="pageSection">
<section class="pageSection col s12">
<p>Welcome to the first Maidstone Hackspace challenge! A great opportunity for all to show off their creative flair and to join our community of makers, tinkerers, artists and more.</p><h2>The Challenge:</h2></section>
<section class="pageSection">
<section class="pageSection col s12">
<p>Design a device which can sort a jar of screws by size, the winning entry will be built by Maidstone Hackspace.</p></section>
<section class="pageSection">
<section class="pageSection col s12">
<p>Concepts can be designed in any software as long as the finished product is viewable without any specialist software e.g.JPG images. If you prefer to paint or draw we accept that too.</p></section>
<section class="pageSection">
<section class="pageSection col s12">
<p>Submissions must be via our mailing list. The closing date is the 31st of July, submissions after this date will not be entered.</p></section>
<section class="pageSection">
<section class="pageSection col s12">
<p><a title="Submit your image here." href="https://groups.google.com/forum/#!forum/maidstone-hackspace" >Submit your image here.</a>
</p></section>
<section class="pageSection">
<section class="pageSection col s12">
<h2>Win a UNO Basic Starter Kit</h2></section>
<section class="pageSection">
<section class="pageSection col s12">
<p><img src="http://imgapp.banggood.com/thumb/large/2014/xiemeijuan/03/SKU208787/SKU208787a.jpg" alt="Arduino starter kit" align="middle" style="margin:auto;display:block;width:500px;" />
This kit comes with an arduino board and various sensors and components, list below of every thing in the kit.<ul class="bullet-list" >
<li>1 x Arduino UNO R3 development board</li>
@ -85,15 +88,14 @@ This kit comes with an arduino board and various sensors and components, list be
<li>1 x 9V battery</li>
<li>1 x 2.54mm 40pin pin header</li>
</ul></p></section>
<footer class="pageFooter">
<footer class="pageFooter col s12">
</footer>
</div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="http://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">Browse Archives</a></form><div style="clear:both;"></div><div></div></div><div>
</div></div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="https://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">View Group</a></form><div style="clear:both;"></div><div></div></div><div>
<!--google analytics-->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<script><!--//--><![CDATA[//><!--!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'http://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
//]]></script>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
<script src="//platform.linkedin.com/in.js" type="text/javascript"> lang: en_US</script>
@ -101,29 +103,6 @@ This kit comes with an arduino board and various sensors and components, list be
//facebook share
(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.3";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));
//]]></script><script type="text/javascript" ><!--//--><![CDATA[//><!--
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
var app = angular.module('myApp', ['ngAnimate']);
app.controller('sliderController', function($scope, $interval) {
@ -166,6 +145,29 @@ app.controller('sliderController', function($scope, $interval) {
});
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
//]]>
</script>

View File

@ -2,48 +2,48 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:sa="/">
<head>
<link rel="stylesheet" id="navigationCss" href="/static/css/materialize.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/default.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/js/jquery-ui/themes/base/jquery-ui.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-navigation-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-action-white.css" media="" type="text/css" />
<link rel="stylesheet" id="navigationCss" href="/static/css/sprite-content-white.css" media="" type="text/css" />
<script type="text/javascript" src="/static/js/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/static/js/jquery-2.2.3.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-animate.js"></script>
<script type="text/javascript" src="/static/js/materialize.js"></script>
<script type="text/javascript" src="/static/js/default.js"></script>
<link rel="icon" type="image/png" href="/static/images/favicon.png">
<title>Maidstone Hackspace</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div id="headerstrip"><nav class="navstrip"><div class="left"><a id="mini_logo" href="/login"><img src="//127.0.0.1:5000/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="social"><div class="btn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="http://maidstone-hackspace.org.uk/">Tweet</a></div><div class="btn"><div class="fb-share-button" data-href="http://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="btn"><script type="IN/Share" data-url="http://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="btn"><div size="standard" class="g-plusone" data-href="http://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<nav id="leftNav" class="menu" >
<div id="headerstrip" class="row"><nav class="navstrip"><div class="navstripleft col s6"><a id="mini_logo" href="/login"><img src="//http://127.0.0.1/static/images/hackspace.png" class="mini-logo"></a><span class="mini-logo-text">Maidstone Hackspace</span></div><div class="col s6 offset-s8 social"><div class="socbtn"><a href="https://twitter.com/share" class="twitter-share-button" data-via="https://maidstone-hackspace.org.uk/" data-hashtags="mhackspace">Tweet</a></div><div class="socbtn"><div class="fb-share-button" data-href="https://maidstone-hackspace.org.uk/" data-layout="button_count"></div></div><div class="socbtn"><script type="IN/Share" data-url="https://maidstone-hackspace.org.uk/" data-counter="right"></script></div><div class="socbtn"><div size="standard" class="g-plusone" data-href="https://maidstone-hackspace.org.uk/" data-size="medium" data-annotation="bubble" count="true"></div></div></div></nav></div>
<div id="menubar" class="row" ><nav class="col s10 offset-s1" >
<ul>
<li class="active mi0"><a href="/" >Home</a></li>
<li class="mi1"><a href="/chat" >Chat</a></li>
<li class="mi2"><a href="/donate" >Donate</a></li>
<li class="mi3"><a href="#mailing-list-signup" >Contact</a></li>
<li class="mi4"><a href="/login" >login</a></li>
<li class="mi3"><a href="/contact-us" >Contact</a></li>
<li class="mi4"><a href="/mailing-list" >Group</a></li>
<li class="mi5"><a href="/login" >Login</a></li>
</ul>
<div style="clear:both;"></div>
</nav>
<div class="page" >
</nav></div>
<div class="row"><div class="page col s10 offset-s1" >
<header class="pageHeader">
Make a donation</header>
<section class="pageSection">
<section class="pageSection col s12">
<p>If you would like to donate to the space please type an amount and use the reference code for what ever your donating for, for example use #lair to donate to getting a space.
We may run pledges in the future for equipment in which case use the reference for the equipment your pledging towards.</p></section>
<section class="pageSection">
<p>Currently raised &pound;5.00 towards #lair target is &pound;1000.00.</p><form action="/donate/submit" method="post" ><fieldset><legend>Donate to Maidstone Hackspace</legend><p><label for="reference">Reference<select name="reference"><option value="#lair" selected="selected">#lair</option></select></label></p><p><label for="amount">Donation Amount<input type="text" name="amount" placeholder="50.00" value="50.00"></label></p><p class="bottom full_width"><button type="submit">submit</button></p></fieldset></form></section>
<footer class="pageFooter">
We may run pledges in the future for equipment in which case use the reference for the equipment your pledging towards.</p><form action="/donate/submit" method="post" ><fieldset><legend>Donate to Maidstone Hackspace</legend><p><label for="provider">GoCardless<input type="radio" name="provider" placeholder="gocardless" value="gocardless" checked="checked"></label></p><p><label for="provider">PayPal<input type="radio" name="provider" placeholder="" value="paypal"></label></p><p><label for="reference">Reference<select name="reference"><option value="#lair" selected="selected">#lair</option></select></label></p><p><label for="amount">Donation Amount<input type="text" name="amount" placeholder="50.00" value="50.00"></label></p><p class="bottom full_width"><button type="submit">submit</button></p></fieldset></form></section>
<footer class="pageFooter col s12">
</footer>
</div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="http://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">Browse Archives</a></form><div style="clear:both;"></div><div></div></div><div>
</div></div>
<div id="footer"><div id="footertop"></div><div id="footerbottom"><div class="container"><div class="copyright">&copy;2016 Maidstone Hackspace</div><div mailing-list-signup class="google-groups-signup"><h3>Signup and make yourself known</h3><form class="block" name="signup" method="get" action="https://groups.google.com/group/maidstone-hackspace/boxsubscribe"><label for="groups-email">Email Address</label><input id="groups-email" name="email" class="required"/><button type="submit" />Subscribe</button><a href="http://groups.google.com/group/maidstone-hackspace">View Group</a></form><div style="clear:both;"></div><div></div></div><div>
<!--google analytics-->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<script><!--//--><![CDATA[//><!--!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'http://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');
//]]></script>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
<script src="//platform.linkedin.com/in.js" type="text/javascript"> lang: en_US</script>
@ -51,29 +51,6 @@
//facebook share
(function(d, s, id) {var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) return;js = d.createElement(s); js.id = id;js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.3";fjs.parentNode.insertBefore(js, fjs);}(document, 'script', 'facebook-jssdk'));
//]]></script><script type="text/javascript" ><!--//--><![CDATA[//><!--
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
var app = angular.module('myApp', ['ngAnimate']);
app.controller('sliderController', function($scope, $interval) {
@ -116,6 +93,29 @@ app.controller('sliderController', function($scope, $interval) {
});
$(document).ready(function(){
$('#mini_logo').on("click", function(e){
e.preventDefault();
$('#member_navigation').toggle();
});
});
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-63373181-1', 'maidstone-hackspace.org.uk');
ga('send', 'pageview');
//]]>
</script>

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

144
website/static/html/index.htm Executable file

File diff suppressed because one or more lines are too long

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

0
website/static/images/background.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

0
website/static/images/background.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

0
website/static/images/badges/art_hacker.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

0
website/static/images/badges/circuit_hacker.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 945 B

After

Width:  |  Height:  |  Size: 945 B

0
website/static/images/badges/code_hacker.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1003 B

After

Width:  |  Height:  |  Size: 1003 B

0
website/static/images/badges/craft_hacker.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
website/static/images/badges/founder.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
website/static/images/badges/handyman.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

0
website/static/images/badges/member.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

0
website/static/images/badges/pledged.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

0
website/static/images/badges/trainer.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 983 B

After

Width:  |  Height:  |  Size: 983 B

0
website/static/images/banners/audio_board.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 KiB

0
website/static/images/banners/hackspace-banner.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
website/static/images/banners/indiegogo.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

0
website/static/images/banners/microscope.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

0
website/static/images/banners/rocket_camera.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

View File

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

0
website/static/images/css/sprite-action-white.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

0
website/static/images/css/sprite-content-white.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

0
website/static/images/css/sprite-navigation-white.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

0
website/static/images/example-01.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

0
website/static/images/example-02.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 65 KiB

0
website/static/images/example-03.jpg Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 38 KiB

0
website/static/images/favicon.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
website/static/images/hackspace-banner.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
website/static/images/hackspace.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Some files were not shown because too many files have changed in this diff Show More