Merge pull request #77 from EbookFoundation/newfoundation

Newfoundation
pull/85/head
Nicholas Antonov 2018-05-16 14:32:37 -04:00 committed by GitHub
commit 4ba506960a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
451 changed files with 87951 additions and 2210 deletions

5
.gitignore vendored
View File

@ -6,11 +6,14 @@ settings/keys/*
*.dot
reports
ENV
venv
.DS_Store
build
deploy/last-update
logs/*
cache/*
celerybeat.pid
celerybeat-schedule
.gitignore~
static/scss/*.css.map
static/scss/**/*.css.map
*.retry

View File

@ -12,7 +12,32 @@ The partitioning between these modules is not as clean as would be ideal. `payme
regluit was originally developed on Django 1.3 (python 2.7) and currently runs on Django 1.8.
Develop
Development (Vagrant + Virtualbox)
-------
The recommended method for local development is to create a virtual machine with [Vagrant](https://www.vagrantup.com/) and [Virtualbox](https://www.virtualbox.org/wiki/Downloads).
With this method, the only requirements on the host machine are `virtualbox` and `vagrant`.
Vagrant will use the `ansible-local` provisioner, therefore installing python and ansible on the host machine is not necessary.
__Instructions for Ubuntu 16:__
1. Install virtualbox: `sudo apt-get install virtualbox`
2. Install vagrant: `sudo apt-get install vagrant`
3. Clone the `EbookFoundation/regluit` repository.
4. Navigate to the base directory of the cloned repo (where `Vagrantfile` is located).
5. Run `vagrant up` to create the VM, install dependencies, and start necessary services.
* Note: This step may take up to 15 minutes to complete.
6. Once the VM has been created, run `vagrant ssh` to log in to the virtual machine you just created. If provisioning was successful, you should see a success message upon login.
* If virtualenv doesn't activate upon login, you can do it manually by running `cd /opt/regluit && source venv/bin/activate`
7. Within the VM, run `./manage.py runserver 0.0.0.0:8000` to start the Django development server.
8. On your host machine, open your web browser of choice and navigate to `http://127.0.0.1:8000`
__Instructions for other platforms (Windows/OSX):__
* Steps are essentially the same, except for the installation of Vagrant and Virtualbox. Refer to each package's documentation for specific installation instructions.
_NOTE:_ If running Windows on your host machine, ensure you are running `vagrant up` from an elevated command prompt, e.g. right click on Command Prompt -> Run As Administrator.
Development (Host Machine)
-------
Here are some instructions for setting up regluit for development on

56
Vagrantfile vendored Normal file
View File

@ -0,0 +1,56 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "ubuntu/xenial64"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
config.vm.box_check_update = false
# Setup specific for local machine
config.vm.define "regluit-local", primary: true do |local|
# Create a private network
local.vm.network "private_network", type: "dhcp"
local.vm.hostname = "regluit-local"
# VirtuaLBox provider settings for running locally with Oracle VirtualBox
# --uartmode1 disconnected is necessary to disable serial interface, which
# is known to cause issues with Ubuntu 16 VM's
local.vm.provider "virtualbox" do |vb|
vb.name = "regluit-local"
vb.memory = 1024
vb.cpus = 2
vb.customize [ "modifyvm", :id, "--uartmode1", "disconnected" ]
end
end
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/opt/regluit"
config.vm.network "forwarded_port", guest: 8000, host: 8000
# Provision node with Ansible running on the Vagrant host
# This requires you have Ansible installed locally
# Vagrant autogenerates an ansible inventory file to use
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "/opt/regluit/provisioning/setup-regluit.yml"
ansible.provisioning_path = "/opt/regluit"
ansible.verbose = true
ansible.install = true
end
config.vm.post_up_message = "Successfully created regluit-local VM. Run 'vagrant ssh' to log in and start the development server."
end

View File

@ -45,7 +45,7 @@ from regluit.payment.parameters import (
TRANSACTION_STATUS_FAILED,
TRANSACTION_STATUS_INCOMPLETE
)
from regluit.utils import crypto
from regluit.utils import encryption as crypto
from regluit.utils.localdatetime import now, date_today
from regluit.core.parameters import (

View File

@ -106,10 +106,10 @@ class Identifier(models.Model):
def __unicode__(self):
return u'{0}:{1}'.format(self.type, self.value)
def label(self):
return ID_CHOICES_MAP.get(self.type, self.type)
def url(self):
return id_url(self.type, self.value)
@ -127,7 +127,7 @@ class Work(models.Model):
is_free = models.BooleanField(default=False)
landings = GenericRelation(Landing, related_query_name='works')
related = models.ManyToManyField('self', symmetrical=False, blank=True, through='WorkRelation', related_name='reverse_related')
age_level = models.CharField(max_length=5, choices=AGE_LEVEL_CHOICES, default='', blank=True)
age_level = models.CharField(max_length=5, choices=AGE_LEVEL_CHOICES, default='', blank=True)
class Meta:
ordering = ['title']
@ -137,7 +137,7 @@ class Work(models.Model):
def __init__(self, *args, **kwargs):
self._last_campaign = None
super(Work, self).__init__(*args, **kwargs)
def id_for(self, type):
return id_for(self, type)
@ -205,7 +205,7 @@ class Work(models.Model):
@property
def openlibrary_url(self):
return id_url('olwk', self.openlibrary_id)
def cover_filetype(self):
if self.uses_google_cover():
return 'jpeg'
@ -403,14 +403,14 @@ class Work(models.Model):
def pdffiles(self):
return EbookFile.objects.filter(edition__work=self, format='pdf').exclude(file='').order_by('-created')
def versions(self):
version_labels = []
for ebook in self.ebooks_all():
if ebook.version_label and not ebook.version_label in version_labels:
version_labels.append(ebook.version_label)
return version_labels
def formats(self):
fmts = []
for fmt in ['pdf', 'epub', 'mobi', 'html']:
@ -422,7 +422,7 @@ class Work(models.Model):
def remove_old_ebooks(self):
# this method is triggered after an file upload or new ebook saved
old = Ebook.objects.filter(edition__work=self, active=True).order_by('-version_iter', '-created')
# keep highest version ebook for each format and version label
done_format_versions = []
for eb in old:
@ -431,7 +431,7 @@ class Work(models.Model):
eb.deactivate()
else:
done_format_versions.append(format_version)
# check for failed uploads.
null_files = EbookFile.objects.filter(edition__work=self, file='')
for ebf in null_files:
@ -768,12 +768,12 @@ class Subject(models.Model):
class Meta:
ordering = ['name']
@classmethod
def set_by_name(cls, subject, work=None, authority=None):
''' use this method whenever you would be creating a new subject!'''
subject = subject.strip()
# make sure it's not a ; delineated list
subjects = subject.split(';')
for additional_subject in subjects[1:]:
@ -798,12 +798,12 @@ class Subject(models.Model):
if not subject_obj.authority and authority:
subject_obj.authority = authority
subject_obj.save()
subject_obj.works.add(work)
return subject_obj
return subject_obj
else:
return None
def __unicode__(self):
return self.name
@ -1082,7 +1082,7 @@ class EbookFile(models.Model):
asking=self.asking,
source=self.file.url
)
new_mobi_ebf.file.save(path_for_file('ebf', None), mobi_cf)
new_mobi_ebf.save()
if self.ebook:
@ -1180,7 +1180,7 @@ class Ebook(models.Model):
return '.{}'.format(self.version_iter)
else:
return '().{}'.format(self.version_label, self.version_iter)
def set_version(self, version):
#set both version_label and version_iter with one string with format "version.iter"
version_pattern = r'(.*)\.(\d+)$'
@ -1190,11 +1190,11 @@ class Ebook(models.Model):
else:
self.version_label = version
self.save()
def set_next_iter(self):
# set the version iter to the next unused iter for that version
for ebook in Ebook.objects.filter(
edition=self.edition,
edition=self.edition,
version_label=self.version_label,
format=self.format,
provider=self.provider
@ -1203,7 +1203,7 @@ class Ebook(models.Model):
break
self.version_iter = iter + 1
self.save()
@property
def rights_badge(self):
if self.rights is None:

View File

@ -292,7 +292,9 @@ class OfferForm(forms.ModelForm):
class CampaignPurchaseForm(forms.Form):
anonymous = forms.BooleanField(required=False, label=_("Make this purchase anonymous, please"))
anonymous = forms.BooleanField(required=False,
label_suffix='',
label=_("Make this purchase anonymous"))
offer_id = forms.IntegerField(required=False)
offer = None
library_id = forms.IntegerField(required=False)
@ -357,7 +359,8 @@ class CampaignPurchaseForm(forms.Form):
class CampaignThanksForm(forms.Form):
anonymous = forms.BooleanField(
required=False,
label=_("Make this contribution anonymous, please")
label_suffix='',
label=_("Make this contribution anonymous")
)
preapproval_amount = forms.DecimalField(
required = True,
@ -391,7 +394,10 @@ class CampaignPledgeForm(forms.Form):
def amount(self):
return self.cleaned_data["preapproval_amount"] if self.cleaned_data else None
anonymous = forms.BooleanField(required=False, label=_("Make this support anonymous, please"))
anonymous = forms.BooleanField(
required=False,
label_suffix='',
label=_("Make this support anonymous"))
ack_name = forms.CharField(
required=False,
max_length=64,

View File

@ -1,22 +1,28 @@
<!DOCTYPE html>
{% load truncatechars %}{% load sass_tags %}
<html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="referrer" content="origin" />
<title>unglue.it {% block title %}{% endblock %}</title>
<link REL="SHORTCUT ICON" HREF="/static/images/favicon.ico">
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@unglueit" />
{% block extra_meta %}{% endblock %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/sitewide4.scss' %}" />
<link REL="SHORTCUT ICON" HREF="/static/images/favicon.ico">
{% block extra_css %}{% endblock %}
<script type="text/javascript" src="{{ jquery_home }}"></script>
<link href="{% sass_src 'scss/global.scss' %}" rel="stylesheet" type="text/css" />
<link href="{% sass_src 'scss/header.scss' %}" rel="stylesheet" type="text/css" />
<link type="text/css" rel="stylesheet" href="/static/css/font-awesome.min.css" />
<script type="text/javascript" src="{{ jquery_home }}"></script>
<script type="text/javascript" src="/static/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/static/js/sitewide1.js"></script>
<script type="text/javascript" src="/static/js/watermark_init.js"></script>
<script type="text/javascript" src="/static/js/watermark_change.js"></script>
<script type="text/javascript" src="/static/js/watermark_init.js"></script>
<script type="text/javascript" src="/static/js/watermark_change.js"></script>
<script defer type="text/javascript" src="/static/js/sitewide1.js"></script>
{% block extra_js %}
{% endblock %}
{% if show_langs %}
@ -45,26 +51,18 @@
</div>
</div>
<div id="js-page-wrap">
<div id="js-header">
<div class="js-main">
<div class="js-logo">
<a href="{% url 'landing' %}"><img src="/static/images/logo.png" alt="unglue.it" title="unglue.it" /></a>
</div>
{% block search_box %}
{% if not suppress_search_box %}
<div class="js-search">
<div class="js-search-inner">
<form action="{% url 'search' %}" method="get">
<div class="inputalign">
<input type="text" id="nowatermark" size="25" onfocus="imgfocus()" onblur="imgblur(15)" class="inputbox" name="q" value="{{ q }}">
<input type="submit" class="button">
</div>
</form>
</div>
</div>
{% endif %}
{% endblock %}
<div id="page-wrapper">
<div id="header">
<div id="header-logo">
<a href="{% url 'landing' %}"><img src="/static/images/logo.png" alt="unglue.it" title="unglue.it"/></a>
</div>
<div id="header-search-bar">
<form action="{% url 'search' %}" method="get">
<input role="search" type="text" placeholder="Search" id="nowatermark" size="25" onfocus="imgfocus()" onblur="imgblur(15)" class="inputbox" name="q" value="{{ q }}"></input>
<i class="fa fa-search"></i>
</form>
</div>
<div id="header-login">
{% block signin %}
{% if user.is_authenticated %}
<div class="js-topmenu" id="authenticated">
@ -99,30 +97,53 @@
</ul>
</div>
{% else %}
<div class="js-topmenu">
<ul class="menu">
<li><a class="notbutton hijax" href="{% url 'superlogin' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}"><span>Sign In</span></a></li>
{% if not suppress_search_box %}
{% if request.get_full_path != "/accounts/register/" %}
<li class="last"><a class="btn btn-signup" href="{% url 'registration_register' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}">Sign Up <i class="fa fa-chevron-right"></i></a></li>
{% endif %}
{% endif %}
</ul>
</div>
<a class="notbutton hijax" href="{% url 'superlogin' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}"><span>Log In</span></a>
<a class="button success" href="{% url 'registration_register' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}">Sign Up</a>
{% endif %}
{% endblock %}
</div>
<div id="header-menu">
<label for="menu-drilldown-box" toggle-header-menu>
<i class="fa fa-bars"></i>
</label>
<div id="top-menu" style="visibility: hidden;">
<ul class="vertical menu drilldown" data-drilldown >
<label for="menu-drilldown-box">
<li toggle-header-menu><a href="#">Back</a></li>
</label>
<li>
<a href="#">Account</a>
<ul class="menu vertical nested">
<li><a href="#">Pledges</a></li>
<li><a href="#">Notices</a></li>
<li><a href="#">Profile Settings</a></li>
<li><a href="#">Sign out</a></li>
</ul>
</li>
<li>
<a href="#">About Unglue.it</a>
<ul class="menu vertical nested">
<li><a href="{% url 'about' %}">Concept</a></li>
<li><a href="https://blog.unglue.it/">Blog</a></li>
<li><a href="{% url 'press' %}">Press</a></li>
<li><a href="http://eepurl.com/fKLfI">Newsletter</a></li>
</ul>
</li>
<li><a href="{% url 'faq' %}">FAQ</a></li>
<li><a href="{% url 'feedback' %}?page={{request.build_absolute_uri|urlencode:""}}">Help</a></li>
</ul>
</div>
</div>
</div>
{% block news %}
{% endblock %}
{% block topsection %}{% endblock %}
{% block content %}{% endblock %}
</div>
{% block topsection %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}
<div id="footer">
<div class="js-main">
<div class="footer utilityheaders">
<div class="column">
<span>About Unglue.it</span>
<ul>
@ -132,7 +153,7 @@
<li><a href="http://eepurl.com/fKLfI">Newsletter</a></li>
</ul>
</div>
<div class="column">
<div class="column show-for-medium">
<span>Your account</span>
<ul>
{% if user.is_authenticated %}
@ -160,33 +181,33 @@
<li><a href="{% url 'libraries' %}">Unglue.it for Libraries</a>
</ul>
</div>
<div class="column">
<div class="column show-for-medium">
<span>Contact</span>
<ul>
<li> <a href="mailto:info@ebookfoundation.org"><i class="fa fa-envelope fa-2x"></i></a> <a href="https://twitter.com/unglueit"><i class="fa fa-twitter fa-2x"></i></a> <a href="https://facebook/com/unglueit"><i class="fa fa-facebook fa-2x"></i></a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
</div>
{% block counter %}
{% if show_google_analytics %}
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-28369982-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
{% endif %}
{% endblock %}
<script type="text/javascript" src="/static/scss/foundation/dist/js/foundation.js"></script>
</body>
</html>

View File

@ -8,7 +8,7 @@
{% block extra_extra_head %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/landingpage4.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/book_panel2.scss' %}" />
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/faq.scss' %}" />
{% endblock %}
@ -21,29 +21,16 @@
{% endblock %}
{% block content %}
<div id="main-container">
<div class="js-main">
<div id="js-leftcol">
{% include "faqmenu.html" %}
{% block subnav %}{% endblock %}
</div>
<div id="js-maincol-fr" class="have-right doc">
<div class="js-maincol-inner">
<div id="content-block">
<div id="js-main-container">
<div class="js-main-container-inner">
{% block doccontent %}
{% endblock %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="faq-container">
<div class="faq-menu">
{% include "faqmenu.html" %}
{% block subnav %}{% endblock %}
</div>
<div class="faq-main doc">
{% block doccontent %}
{% endblock %}
</div>
</div>
{% endblock %}

View File

@ -17,7 +17,6 @@ location.hash = "#2";
</script>
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
{% endblock %}
{% block topsection %}

View File

@ -14,7 +14,6 @@
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript" src="/static/js/hijax_unglued.js"></script>
<script type="text/javascript" src="/static/js/tabs.js"></script>

View File

@ -10,7 +10,6 @@
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript" src="/static/js/tabs.js"></script>
{% endblock %}

View File

@ -13,175 +13,142 @@
<!-- select {% sass_src 'scss/enhanced_download.scss' %} or {% sass_src 'scss/enhanced_download_ie.scss' %} -->
<script type="text/javascript" src="/static/js/download_page.js"></script>
<script type="text/javascript">
var $j = jQuery.noConflict();
$j(document).ready(function() {
// actually trigger the download_page function
$j(document).trigger('prettifyDownload');
});
var $j = jQuery.noConflict();
$j(document).ready(function() {
// actually trigger the download_page function
$j(document).trigger('prettifyDownload');
});
</script>
{% endblock %}
{% block extra_css %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/download.scss' %}" />
{% endblock %}
{% block avatar %}
<img class="user-avatar" src="/static/images/header/avatar.png" height=36 width="36" alt="private" title="private" />
<img class="user-avatar" src="/static/images/header/avatar.png" height=36 width="36" alt="private" title="private" />
{% endblock %}
{% block content %}
<div class="download_container">
<div id="lightbox_content">
<span id="dropboxjs" data-app-key="{{ dropbox_key }}"></span>
{% if show_beg %}
{% if work.last_campaign.ask_money %}
<div class="border" style="padding: 10px; min-height: 18em">
<div id="askblock">
<div>Please help us thank the creators for making <a href="{% url 'work' work.id %}">{{ work.title }}</a> free. The amount is up to you.</div>
<div id="download_content">
<span id="dropboxjs" data-app-key="{{ dropbox_key }}"></span>
{% if show_beg %}
{% if work.last_campaign.ask_money %}
<div class="rh_ask">
{{ work.last_campaign.description|safe }}
<div class="clearfix"></div>
</div>
<div id="askblock" class="card">
<div>Say thank you for making <a href="{% url 'work' work.id %}">{{ work.title }}</a> free.</div>
<form class="askform" method="POST" action="{% url 'thank' work.id %}#">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="contrib_amount">Amount: {{ form.preapproval_amount.errors }}${{ form.preapproval_amount }}</div>
<div style="text-align: center;"><input name="pledge" type="submit" value="Say Thank You" id="contribsubmit" class="loader-gif" /></div>
<div id="anoncontribbox"><I>{{ form.anonymous.label_tag }}</I> {{ form.anonymous.errors }}{{ form.anonymous }}</div>
{% if request.user.credit.available > 0 %}
<div > You have an available credit of ${{ request.user.credit.available|intcomma }} which will be applied to your contribution.</div>
{% endif %}
</form>
</div>
<div class="rh_ask">
{{ work.last_campaign.description|safe }}
</div>
</div>
{% else %}
<div class="border" style="padding: 10px">
<div class="rh_ask">
{{ work.last_campaign.description|safe }}
</div>
</div>
{% endif %}
{% endif %}
{% if user_license.thanked %}
<div style="text-align: center; padding: 20px;">
<div style="background: #edf3f4; padding: 10px; width:35%; display: inline; ">
You have supported this free book!
</div>
</div>
{% endif %}
{% if lib_thanked %}
<div style="text-align: center; padding: 20px;">
<div style="background: #edf3f4; padding: 10px; width:35%; display: inline; ">
Your library has supported this free book!
</div>
</div>
{% endif %}
{% if amount %}
<div style="text-align: center; padding: 20px;">
<div style="background: #edf3f4; padding: 10px; width:35%; display: inline; ">
Your contribution of ${{amount}} is confirmed.
{% if request.session.receipt %}
A confirmation is being sent to {{ request.session.receipt }}.
{% endif %}
</div>
</div>
{% endif %}
{% if source %}
{% else %}
<div class="border">
<h2 style="width:60%">Downloads for <I><a href="{% url 'work' work.id %}">{{ work.title }}</a></i></h2>
<div class="sharing ebook_download_container">
<h3 class="jsmod-title"><span>Share</span></h3>
<ul class="social menu">
{% with site.domain as domain %}
<a href="https://www.facebook.com/sharer.php?u=https://{{ site.domain }}{% url 'work' work.id|urlencode:"" %}"><li class="facebook first"><span>Facebook</span></li></a>
<a href="https://twitter.com/intent/tweet?url=https://{{ site.domain }}{% url 'work' work.id|urlencode:"" %}&amp;text=I%27m%20enjoying%20{{ work.title|urlencode }}%2C%20a%20free%2C%20non%2DDRM%20ebook%2E%20You%20can%20too%21"><li class="twitter"><span>Twitter</span></li></a>
{% endwith %}
{% if request.user.is_authenticated %}<a href="{% url 'emailshare' 'downloaded' %}?next={% url 'work' work.id %}"><li class="email"><span>Email</span></li></a>{% endif %}
<a id="embed2"><li class="embed"><span>Embed</span></li></a>
<div id="widgetcode2">Copy/paste this into your site:<br /><textarea rows="7" cols="22">&lt;iframe src="https://{{ request.META.HTTP_HOST }}/api/widget/{{ work.first_isbn_13 }}/" width="152" height="325" frameborder="0"&gt;&lt;/iframe&gt;</textarea></div>
</ul>
</div>
{% if xfer_url or can_kindle %}
<div class="one_click clearfix">
<h3>One-click options</h3>
{% if mac_ibooks and xfer_url %}
<div id="mac_ibooks" title="{{ work.id }}" >
<div class="btn_support mac_ibooks"><a href="{{ xfer_url }}">Load to iBooks</a></div>
</div>
{% endif %}
{% if can_kindle %}
<div id="kindle_div">
{% if request.user.is_authenticated and request.user.profile.kindle_email %}
<div class="yes_js">
<div id="kindle" class="btn_support authenticated" title="{{ work.id }}" >
<a>Send to Kindle</a>
</div>
</div>
<div class="no_js">
<form method="POST" class="btn_support" action="{% url 'send_to_kindle' work.id 0 %}">
<input type="submit" value="Send to Kindle">
</form>
</div>
{% else %}
<div class="btn_support kindle {% if request.user.is_anonymous %}modify{% endif %}">
<a href="{% url 'kindle_config_download' work.id %}">Set up Kindle </a>
</div>
{% endif %}
</div>
{% endif %}
{% if xfer_url %}
{% if iOS %}
<div id="marvin" title="{{ work.id }}" >
<div class="btn_support marvin"><a href="marvinhttp://{{ xfer_url|urlencode }}">Load to Marvin</a></div>
<div class="input-group">
{{ form.preapproval_amount.errors }}
<span class="input-group-label">$</span>
<input class="input-group-field" type="number" min="0.99" max="1999.99" step="1.00"
id="id_preapproval_amount" name="preapproval_amount"
value="{{ form.preapproval_amount.value }}">
<div class="input-group-button">
<input name="pledge" type="submit" class="button loader-gif" value="Say Thanks" id="contribsubmit">
</div>
</div>
<div id="anoncontribbox">
{{ form.anonymous.errors }}{{ form.anonymous }}
<i class="inline-block">{{ form.anonymous.label_tag }}</i>
</div>
{% if request.user.credit.available > 0 %}
<div > You have an available credit of ${{ request.user.credit.available|intcomma }} which will be applied to your contribution.</div>
{% endif %}
{% endif %}
{% if can_kindle %}{% if not request.user.is_authenticated %}
<div style="clear:left"> You'll need an unglue.it account to <i>Send to Kindle</i>.</div>
{% endif %}{% endif %}
</form>
</div>
{% else %}
<div class="rh_ask">
{{ work.last_campaign.description|safe }}
<div class="clearfix"></div>
</div>
{% endif %}
<div class="ebook_download_container">
{% if testmode %}
<i>Download links for uploaded files will appear here when campaign is launched.</i>
{% endif %}
{% if unglued_ebooks or other_ebooks or acq %}
{% if unglued_ebooks %}
<h3>Download the unglued edition</h3>
<div class="ebook_download">
{% for ebook in unglued_ebooks %}
<a href="{% url 'download_ebook' ebook.id %}">
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a>
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
{% if not forloop.last %}<br /><br />{% endif %}
{% endfor %}
</div>
{% endif %}
{% if other_ebooks %}
{% if unglued_ebook %}
<h4>Download other freely available editions</h4>
{% else %}
<h4>Download freely available editions</h4>
{% endif %}
{% if user_license.thanked %}
<div>
You have supported this free book!
</div>
{% endif %}
{% if lib_thanked %}
<div>
Your library has supported this free book!
</div>
{% endif %}
{% if amount %}
<div>
Your contribution of ${{amount}} is confirmed.
{% if request.session.receipt %}
A confirmation is being sent to {{ request.session.receipt }}.
{% endif %}
<div class="ebook_download">
{% for ebook in other_ebooks %}
<a href="{% url 'download_ebook' ebook.id %}">
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %} at {{ ebook.provider }}</a>
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
{% if not forloop.last %}<br /><br />{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% if acq %}
{% if work.last_campaign.type == 2 %}
<h3>Download your ebook{% if acq.lib_acq %}{% if acq.on_reserve %}, on reserve for you at{% else %}, on loan to you at{% endif %} {{ acq.lib_acq.user.library }}{% endif %}</h3>
<div class="ebook_download">
{% if source %}
{% else %}
<div class="download-body">
<h1 class="h2">Downloads for <I><a href="{% url 'work' work.id %}">{{ work.title }}</a></i></h1>
<div class="ebook_download_container">
{% if testmode %}
<i>Download links for uploaded files will appear here when campaign is launched.</i>
{% endif %}
{% if unglued_ebooks or other_ebooks or acq %}
{% if unglued_ebooks %}
<h2 class="h4">Download the unglued edition</h2>
<div class="ebook_download">
{% for ebook in unglued_ebooks %}
<a href="{% url 'download_ebook' ebook.id %}">
<img src="{{ ebook.rights_badge }}" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" /></a>
<a href="{% url 'download_ebook' ebook.id %}"><img src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }}" title="{{ ebook.format }}" /></a>
<a href="{% url 'download_ebook' ebook.id %}">{{ ebook.format }}</a> {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}
{% if ebook.is_direct %}<a class="dropbox-saver" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>{% endif %}
{% if not forloop.last %}<br /><br />{% endif %}
{% endfor %}
</div>
{% endif %}
{% if other_ebooks %}
{% if unglued_ebook %}
<h2 class="h4">Download other freely available editions</h2>
{% else %}
<h2 class="h4">Download freely available editions</h2>
{% endif %}
<div class="ebook_download">
{% for ebook in other_ebooks %}
<div class="download_option flexible card">
<a href="{% url 'download_ebook' ebook.id %}" class="download-label h4">
<span class="hide-for-medium" >
{{ebook.format}}:
</span>
<img class="hide-for-small-only" src="/static/images/{{ ebook.format }}32.png" height="32" alt="{{ ebook.format }} at {{ebook.provider}}" title="{{ ebook.format }} at {{ebook.provider}}" />
<span class="hide-for-small-only" >
{{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %} at {{ ebook.provider }}
</span>
</a>
<a href="{% url 'download_ebook' ebook.id %}" class="download-centered hide-for-medium">
<i class="fa fa-download fa-2x" title="Download {{ebook.format}}"></i>
</a>
{% if ebook.is_direct %}
<span class="dropbox_download_option download-centered" >
<a class="dropbox-saver download-centered" href="{{ ebook.download_url }}" data-filename="unglueit-{{ work.id }}.{{ ebook.format }}"></a>
</span>
<span class="download-centered hide-for-small-only">
<img src="{{ ebook.rights_badge }}" class="" alt="{{ ebook.rights}}" title="{{ ebook.rights}}" />
</span>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{% if acq %}
{% if work.last_campaign.type == 2 %}
<h2 class="h4">Download your ebook{% if acq.lib_acq %}{% if acq.on_reserve %}, on reserve for you at{% else %}, on loan to you at{% endif %} {{ acq.lib_acq.user.library }}{% endif %}</h2>
<div class="ebook_download">
<a href="{{ formats.epub }}"><img src="/static/images/epub32.png" height="32" alt="epub" title="epub" /></a>
<a href="{{ formats.epub }}">EPUB</a> (for iBooks, Nook, Kobo)
<a class="dropbox-saver" href="{{ xfer_url }}" data-filename="unglueit-{{ work.id }}.epub"></a>
@ -189,238 +156,293 @@ $j(document).ready(function() {
<a href="{{ formats.mobi }}"><img src="/static/images/mobi32.png" height="32" alt="mobi" title="mobi" /></a>
<a href="{{ formats.mobi }}">MOBI</a> (for Kindle)
<a class="dropbox-saver" href="{{ kindle_url }}" data-filename="unglueit-{{ work.id }}.mobi"></a>
</div>
{% endif %}
{% endif %}
{% else %}
<div class="card">
<p id="content-block">There are no freely available downloads of <I>{{ work.title }}</I> right now. {% if not work in request.user.wishlist.works.all %}Would you like there to be? <a class="add-wishlist"><span class="work_id" id="w{{ work.id }}">Add this book to your wishlist.</span></a>{% else %}Ask your friends to add it to their favorites!{% endif %}</p>
<p>If you know of a Creative-Commons-licensed or US public domain edition of this book, you can add it through the <a href="{% url 'work' work.id %}?tab=4">More... tab of the book page</a>.</p>
</div>
</div>
{% endif %}
{% endif %}
{% else %}
<div class="border">
<p id="content-block">There are no freely available downloads of <I>{{ work.title }}</I> right now. {% if not work in request.user.wishlist.works.all %}Would you like there to be? <a class="add-wishlist"><span class="work_id" id="w{{ work.id }}">Add this book to your wishlist.</span></a>{% else %}Ask your friends to add it to their favorites!{% endif %}</p>
<p>If you know of a Creative-Commons-licensed or US public domain edition of this book, you can add it through the <a href="{% url 'work' work.id %}?tab=4">More... tab of the book page</a>.</p>
</div>
</div>
{% endif %}
<div class="clearfix"></div>
</div>
{% if unglued_ebooks or other_ebooks or acq %}
<div class="border">
<h3>Need instructions?</h3>
<div class="instructions">
<div id="iOS_app_div"{% if iOS_app %} class="active"{% endif %}>
<p>
Looks like you're using an embedded browser inside an iOS app. (Maybe you followed a link in Twitter or Facebook?)
</p>
<p>
{% if formats.epub or formats.mobi %}
To read this ebook you should open this page in safari, or use one of the "One-click" buttons, above. <br />
{% if iphone %}<img width="357" height="156" src="/static/images/clickhere.png" alt="how to open in safari" />{% else %}<img width="500" height="403" src="/static/images/open_safari.png" alt="how to open in safari" />{% endif %}<br clear="left" />
{% if xfer_url or can_kindle %}
<div class="one_click clearfix">
<h2 class="h4">One-click options</h2>
{% if mac_ibooks and xfer_url %}
<div id="mac_ibooks" title="{{ work.id }}" >
<div class="btn_support mac_ibooks"><a href="{{ xfer_url }}">Load to iBooks</a></div>
</div>
{% endif %}
{% if formats.pdf %}
You should also be able to use the <a href="{{ formats.pdf }}">pdf</a> file.
{% elif formats.html %}
You can read the <a href="{{ formats.html }}">HTML version</a> of this book right here in this browser.
{% elif formats.text %}
You can read the <a href="{{ formats.text }}">text version</a> of this book right here in this browser.
{% endif %}
</p>
<p class="other_instructions_paragraph">
Not on iOS? Try the instructions for <a class="android other_instructions">Android</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
<div id="ios_div"{% if iOS %}{% if not iOS_app %} class="active"{% endif %}{% endif %}>
<h4>iOS devices</h4>
{% if formats.epub %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.epub }}">epub file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="ebook_download logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li><a href="https://itunes.apple.com/us/app/ibooks/id364709193?mt=8">Download the free iBooks app</a> from the App Store.</li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>You will be given the option of opening the file in iBooks.</li>
</ul>
<p class="ebook_download logo"><img src="/static/images/marvin_logo.jpg" alt="Marvin Logo" />Marvin is a great way to read ebooks. </p>
<ul>
<li><a href="https://itunes.apple.com/us/app/marvin-ebook-reader-for-epub/id667361209?ls=1&mt=8">Install Marvin</a> from the App Store.</li>
<li>Click the "Load to Marvin" button above.</li>
</ul>
<p class="ebook_download logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />So is Aldiko.</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% elif formats.pdf %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.pdf }}">pdf file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="ebook_download logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li><a href="https://itunes.apple.com/us/app/ibooks/id364709193?mt=8">Download the free iBooks app</a> from the App Store.</li>
<li>Download the <a href="{{ formats.pdf }}">pdf file</a>.</li>
<li>You will be given the option of opening the file in iBooks.</li>
</ul>
{% elif formats.html %}
<p>
Download the <a href="{{ formats.html }}">HTML version</a>.
</p>
{% elif formats.text %}
<p>
Download the <a href="{{ formats.text }}">text version</a>.
</p>
{% else %}
<p>
This ebook is only available in .mobi. Your best bet is to install the free Amazon Kindle app from the Apple Store and then use the Send-to-Kindle option above.
</p>
{% endif %}
<p class="other_instructions_paragraph">
Not on iOS? Try the instructions for <a class="android other_instructions">Android</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
<div id="android_div"{% if android %} class="active"{% endif %}>
<h4>Android devices</h4>
{% if formats.epub %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.epub }}">epub file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="ebook_download logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />Aldiko</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% else %}{% if formats.pdf %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.pdf }}">pdf file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="ebook_download logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />Aldiko</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.pdf }}">pdf file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% else %}{% if formats.html %}
<p>
Download the <a href="{{ formats.html }}">HTML version</a>.
</p>
{% else %}{% if formats.text %}
<p>
Download the <a href="{{ formats.text }}">text version</a>.
</p>
{% else %}
<p>
This ebook is only available in .mobi. Your best bet is to install the free Amazon Kindle app from Google Play and then use the Send-to-Kindle option above.
</p>
{% endif %}{% endif %}{% endif %}{% endif %}
<p class="other_instructions_paragraph">
Not on Android? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
<div id="desktop_div"{% if desktop %} class="active"{% endif %}>
<h4>Reading on a {% if mac_ibooks %}Mac{% else %}PC, Mac, or Linux{% endif %}</h4>
{% if formats.pdf %}
<p>
You probably already have an app which reads PDFs. Download the <a href="{{ formats.pdf }}">pdf file</a> and open it.
</p>
{% elif formats.epub %}
{% if mac_ibooks %}
<p class="ebook_download logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li>The iBooks app is pre-installed with your system software.</li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>. You should be offered the choice to open it in iBooks</li>
</ul>
{% endif %}
<p class="ebook_download logo"><img src="/static/images/calibre_logo.png" alt="Calibre Logo" />Calibre</p>
<ul>
<li><a href="http://calibre-ebook.com/download">Download the free Calibre app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>Open the file in Calibre.</li>
<li>You can <a href="http://blog.marvinapp.com/post/53438723356">use a Calibre plugin</a> to manage files on reader apps.
</ul>
{% elif formats.mobi %}
<p class="ebook_download logo"><img src="/static/images/calibre_logo.png" alt="Calibre Logo" />Calibre</p>
<ul>
<li><a href="http://calibre-ebook.com/download">Download the free Calibre app.</a></li>
<li>Download the <a href="{{ formats.mobi }}">mobi file</a>.</li>
<li>Open the file in Calibre.</li>
<li>You can <a href="http://blog.marvinapp.com/post/53438723356">use a Calibre plugin</a> to manage files on reader apps.
</ul>
{% elif formats.html %}
<p>
You can read the <a href="{{ formats.html }}">HTML version</a> right here in your browser.
</p>
{% else %}
<p>
You can read the <a href="{{ formats.text }}">text version</a> right here in your browser.
</p>
{% endif %}
<p class="other_instructions_paragraph">
Not on a desktop computer, or want to "side-load" ebooks onto a device or app? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="android other_instructions">Android</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
<div id="ereader_div"{% if desktop %} class="active"{% endif %}>
<h4>Ereaders (Kindle, Nook, Kobo, etc.)</h4>
{% if formats.mobi or formats.pdf or formats.epub %}
<ul>
<li>
{% if formats.mobi %}
<b>Kindle</b>: download the <a href="{{ formats.mobi }}">mobi file</a> to your computer, or use the <i>Send To Kindle</i> button above.
{% elif formats.pdf %}
<b>Kindle</b>: download the <a href="{{ formats.pdf }}">pdf file</a> to your computer, or use the <i>Send To Kindle</i> button above.
{% if can_kindle %}
<div id="kindle_div">
{% if request.user.is_authenticated and request.user.profile.kindle_email %}
<div class="yes_js">
<div id="kindle" class="authenticated" title="{{ work.id }}" >
<a class="button success" >Send to Kindle</a>
</div>
</div>
<div class="no_js">
<form method="POST" action="{% url 'send_to_kindle' work.id 0 %}">
<input class="button success" type="submit" value="Send to Kindle">
</form>
</div>
{% else %}
<b>Kindle</b>: We're sorry; we don't have a version suitable for Kindle.
<a class="button secondary" href="{% url 'kindle_config_download' work.id %}">Set up Send to Kindle </a>
{% endif %}
</div>
{% endif %}
{% if xfer_url %}
{% if iOS %}
<div id="marvin" title="{{ work.id }}" >
<a class="button success" href="marvinhttp://{{ xfer_url|urlencode }}">Load to Marvin</a>
</div>
{% endif %}
{% endif %}
{% if can_kindle %}{% if not request.user.is_authenticated %}
<div> You'll need an unglue.it account to <i>Send to Kindle</i>.</div>
{% endif %}{% endif %}
</div>
{% endif %}
<div class="clearfix"></div>
</div>
{% if unglued_ebooks or other_ebooks or acq %}
<h2 class="h4">Need Instructions?</h2>
<ul class="accordion flex_ul" data-accordion data-allow-all-closed="true" data-multi-expand="true">
<li class="accordion-item {% if iOS_app %}is-active{% endif %}" data-accordion-item style="order: {% if iOS_app %} 0 {% else %} 1 {% endif %}">
<a href="#" class="accordion-title">iOS App</a>
<div class="accordion-content" data-tab-content>
<p>
Looks like you're using an embedded browser inside an iOS app. (Maybe you followed a link in Twitter or Facebook?)
</p>
<p>
{% if formats.epub or formats.mobi %}
To read this ebook you should open this page in safari, or use one of the "One-click" buttons, above. <br />
{% if iphone %}<img width="357" height="156" src="/static/images/clickhere.png" alt="how to open in safari" />{% else %}<img width="500" height="403" src="/static/images/open_safari.png" alt="how to open in safari" />{% endif %}<br clear="left" />
{% endif %}
{% if formats.pdf %}
You should also be able to use the <a href="{{ formats.pdf }}">pdf</a> file.
{% elif formats.html %}
You can read the <a href="{{ formats.html }}">HTML version</a> of this book right here in this browser.
{% elif formats.text %}
You can read the <a href="{{ formats.text }}">text version</a> of this book right here in this browser.
{% endif %}
</p>
<p class="other_instructions_paragraph">
Not on iOS? Try the instructions for <a class="android other_instructions">Android</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
</li>
<li class="accordion-item {% if iOS_app %}{% if not iOS_app %}is-active{% endif %}{% endif %}" data-accordion-item style="order: {% if iOS_app %}{% if not iOS_app %} 0 {% else %} 2 {% endif %} {% else %} 2 {% endif %}">
<a href="#" class="accordion-title">iOS</a>
<div class="accordion-content" data-tab-content>
<h4>iOS devices</h4>
{% if formats.epub %}
<b>All other ereaders</b>: download the <a href="{{ formats.epub }}">epub file</a> to your computer.
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.epub }}">epub file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li><a href="https://itunes.apple.com/us/app/ibooks/id364709193?mt=8">Download the free iBooks app</a> from the App Store.</li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>You will be given the option of opening the file in iBooks.</li>
</ul>
<p class="logo"><img src="/static/images/marvin_logo.jpg" alt="Marvin Logo" />Marvin is a great way to read ebooks. </p>
<ul>
<li><a href="https://itunes.apple.com/us/app/marvin-ebook-reader-for-epub/id667361209?ls=1&mt=8">Install Marvin</a> from the App Store.</li>
<li>Click the "Load to Marvin" button above.</li>
</ul>
<p class="logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />So is Aldiko.</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% elif formats.pdf %}
<b>All other ereaders</b>: download the <a href="{{ formats.pdf }}">pdf file</a> to your computer.
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.pdf }}">pdf file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li><a href="https://itunes.apple.com/us/app/ibooks/id364709193?mt=8">Download the free iBooks app</a> from the App Store.</li>
<li>Download the <a href="{{ formats.pdf }}">pdf file</a>.</li>
<li>You will be given the option of opening the file in iBooks.</li>
</ul>
{% elif formats.html %}
<p>
Download the <a href="{{ formats.html }}">HTML version</a>.
</p>
{% elif formats.text %}
<p>
Download the <a href="{{ formats.text }}">text version</a>.
</p>
{% else %}
<b>All other ereaders</b>: We're sorry; we don't have a version suitable for your device.
<p>
This ebook is only available in .mobi. Your best bet is to install the free Amazon Kindle app from the Apple Store and then use the Send-to-Kindle option above.
</p>
{% endif %}
</li>
<li>Plug the ereader into your computer with a USB cable.</li>
<li>Using the Finder (Mac) or Windows Explorer (Windows), drag and drop the ebook file into the Documents folder on your device. (It may also be called My Documents or My Stuff, depending on your ereader.)</li>
<li>Eject your device from the Finder or Explorer and disconnect the USB.</li>
<li>You may need to reboot your device to see the new book.</li>
</ul>
{% else %}
<p>
We're sorry; we don't have a file format suitable for ereaders.
</p>
{% endif %}
<p class="other_instructions_paragraph">
Not using an ereader? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="android other_instructions">Android</a>, or <a class="desktop other_instructions">desktop computers</a>.
</p>
</div>
<div id="ereader_div" class="active">
<h4>Dropbox</h4>
<p class="other_instructions_paragraph"> Dropbox is a good way to share your ebooks between desktop, tablet and smartphone. If you see a dropbox button above, click it to load your books into your dropbox folder. Then load the file into your reader application on your device.
</p>
<p class="other_instructions_paragraph">
Not on iOS? Try the instructions for <a class="android other_instructions">Android</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
</li>
<li class="accordion-item {% if android %}is-active{% endif %}" data-accordion-item style="order: {% if android %} 0 {% else %} 3 {% endif %}">
<a href="#" class="accordion-title">Android</a>
<div class="accordion-content" data-tab-content>
<h4>Android devices</h4>
{% if formats.epub %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.epub }}">epub file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />Aldiko</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% else %}{% if formats.pdf %}
<p>
You may already have an app which reads ebooks. Download the <a href="{{ formats.pdf }}">pdf file</a> and see if you're offered an option for opening the file. If so, you're done! If not...
</p>
<p class="logo"><img src="/static/images/aldiko_logo.png" alt="Aldiko Logo" />Aldiko</p>
<ul>
<li><a href="http://www.aldiko.com/">Download the free Aldiko app.</a></li>
<li>Download the <a href="{{ formats.pdf }}">pdf file</a>.</li>
<li>When the download is complete, tap it in your notifications menu. It will be added to Aldiko, ready to read next time you open the app.</li>
</ul>
{% else %}{% if formats.html %}
<p>
Download the <a href="{{ formats.html }}">HTML version</a>.
</p>
{% else %}{% if formats.text %}
<p>
Download the <a href="{{ formats.text }}">text version</a>.
</p>
{% else %}
<p>
This ebook is only available in .mobi. Your best bet is to install the free Amazon Kindle app from Google Play and then use the Send-to-Kindle option above.
</p>
{% endif %}{% endif %}{% endif %}{% endif %}
<p class="other_instructions_paragraph">
Not on Android? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="desktop other_instructions">desktop computers</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
</li>
<li class="accordion-item {% if desktop %}is-active{% endif %}" data-accordion-item style="order: {% if desktop %} 0 {% else %} 4 {% endif %}">
<a href="#" class="accordion-title">Desktop</a>
<div class="accordion-content" data-tab-content>
<h4>Reading on a {% if mac_ibooks %}Mac{% else %}PC, Mac, or Linux{% endif %}</h4>
{% if formats.pdf %}
<p>
You probably already have an app which reads PDFs. Download the <a href="{{ formats.pdf }}">pdf file</a> and open it.
</p>
{% elif formats.epub %}
{% if mac_ibooks %}
<p class="logo"><img src="/static/images/ibooks_logo.jpg" alt="iBooks Logo" />iBooks</p>
<ul>
<li>The iBooks app is pre-installed with your system software.</li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>. You should be offered the choice to open it in iBooks</li>
</ul>
{% endif %}
<p class="logo"><img src="/static/images/calibre_logo.png" alt="Calibre Logo" />Calibre</p>
<ul>
<li><a href="http://calibre-ebook.com/download">Download the free Calibre app.</a></li>
<li>Download the <a href="{{ formats.epub }}">epub file</a>.</li>
<li>Open the file in Calibre.</li>
<li>You can <a href="http://blog.marvinapp.com/post/53438723356">use a Calibre plugin</a> to manage files on reader apps.
</ul>
{% elif formats.mobi %}
<p class="logo"><img src="/static/images/calibre_logo.png" alt="Calibre Logo" />Calibre</p>
<ul>
<li><a href="http://calibre-ebook.com/download">Download the free Calibre app.</a></li>
<li>Download the <a href="{{ formats.mobi }}">mobi file</a>.</li>
<li>Open the file in Calibre.</li>
<li>You can <a href="http://blog.marvinapp.com/post/53438723356">use a Calibre plugin</a> to manage files on reader apps.
</ul>
{% elif formats.html %}
<p>
You can read the <a href="{{ formats.html }}">HTML version</a> right here in your browser.
</p>
{% else %}
<p>
You can read the <a href="{{ formats.text }}">text version</a> right here in your browser.
</p>
{% endif %}
<p class="other_instructions_paragraph">
Not on a desktop computer, or want to "side-load" ebooks onto a device or app? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="android other_instructions">Android</a>, or <a class="ereader other_instructions">ereaders (Kindle, Nook, Kobo, etc.)</a>.
</p>
</div>
</li>
<li class="accordion-item {% if desktop %}is-active{% endif %}" data-accordion-item style="order: {% if desktop %} 0 {% else %} 5 {% endif %}">
<a href="#" class="accordion-title">E-Readers</a>
<div class="accordion-content" data-tab-content>
<h4>Ereaders (Kindle, Nook, Kobo, etc.)</h4>
{% if formats.mobi or formats.pdf or formats.epub %}
<ul>
<li>
{% if formats.mobi %}
<b>Kindle</b>: download the <a href="{{ formats.mobi }}">mobi file</a> to your computer, or use the <i>Send To Kindle</i> button above.
{% elif formats.pdf %}
<b>Kindle</b>: download the <a href="{{ formats.pdf }}">pdf file</a> to your computer, or use the <i>Send To Kindle</i> button above.
{% else %}
<b>Kindle</b>: We're sorry; we don't have a version suitable for Kindle.
{% endif %}
{% if formats.epub %}
<b>All other ereaders</b>: download the <a href="{{ formats.epub }}">epub file</a> to your computer.
{% elif formats.pdf %}
<b>All other ereaders</b>: download the <a href="{{ formats.pdf }}">pdf file</a> to your computer.
{% else %}
<b>All other ereaders</b>: We're sorry; we don't have a version suitable for your device.
{% endif %}
</li>
<li>Plug the ereader into your computer with a USB cable.</li>
<li>Using the Finder (Mac) or Windows Explorer (Windows), drag and drop the ebook file into the Documents folder on your device. (It may also be called My Documents or My Stuff, depending on your ereader.)</li>
<li>Eject your device from the Finder or Explorer and disconnect the USB.</li>
<li>You may need to reboot your device to see the new book.</li>
</ul>
{% else %}
<p>
We're sorry; we don't have a file format suitable for ereaders.
</p>
{% endif %}
<p class="other_instructions_paragraph">
Not using an ereader? Try the instructions for <a class="ios other_instructions">iPhone/iPad</a>, <a class="android other_instructions">Android</a>, or <a class="desktop other_instructions">desktop computers</a>.
</p>
</div>
</li>
<li class="accordion-item {% if desktop %}is-active{% endif %}" data-accordion-item style="order: {% if desktop %} 0 {% else %} 6 {% endif %}">
<a href="#" class="accordion-title">Dropbox</a>
<div class="accordion-content" data-tab-content>
<h4>Dropbox</h4>
<p class="other_instructions_paragraph"> Dropbox is a good way to share your ebooks between desktop, tablet and smartphone. If you see a dropbox button above, click it to load your books into your dropbox folder. Then load the file into your reader application on your device.
</p>
</div>
</li>
</ul>
<div class="download_footer card">
<h4>Need more help?</h4>
<p><a href="{% url 'feedback' %}?page={{request.build_absolute_uri|urlencode:""}}">Ask us a question!</a></p>
<div>
<a href="https://www.defectivebydesign.org/drm-free">
<img src="/static/images/DRM-free150.png" alt="DefectiveByDesign.org" border="0" align="middle" />
</a>
<span>
All downloads from Unglue.it are DRM free. Hooray!
</span>
</div>
</div>
{% endif %}
{% endif %}
</div>
<br />
<h4>Need more help?</h4>
<p><a href="{% url 'feedback' %}?page={{request.build_absolute_uri|urlencode:""}}">Ask us a question!</a></p>
<div>
<a href="http://www.defectivebydesign.org/drm-free"><img src="/static/images/DRM-free150.png" alt="DefectiveByDesign.org" border="0" align="middle" /></a> All downloads from Unglue.it are DRM free. Hooray!
</div>
</div>
{% else %}
{% endif %}
{% endif %}
</div>
</div>
<script type="text/javascript" src="/static/js/dropins.js" ></script>
{% endblock %}

View File

@ -14,7 +14,6 @@
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript" src="/static/js/hijax_unglued.js"></script>
<script type="text/javascript" src="/static/js/tabs.js"></script>

View File

@ -16,11 +16,11 @@ Read the ebook now, help to make if available to all in the future. The eBook wa
<dd>The ungluing date is the date a book gets released under a Creative Commons License. After the ungluing date, the ebook will be available for free at unglue.it, Internet Archive and any library, anywhere. You'll be able to make copies for all your friends, if that's what you want to do.</dd>
<dt>How does that work?</dt>
<dd>The rights holder for the book picks
<dd>The rights holder for the book picks
<ol>
<li>an initial ungluing date some time in the future, and </li>
<li>a revenue goal</li>
</ol> When an ebook license is purchased, the ungluing date is recalculated according to these formulae:<pre>
</ol> When an ebook license is purchased, the ungluing date is recalculated according to these formulae:<pre class="long-formula">
(days per dollar) = [(initial ungluing date) - (launch date)] / (campaign goal)
(current ungluing date) = (initial ungluing date) - (gross revenue)*(days per dollar)
@ -35,12 +35,12 @@ Here's a calculator you can use to see how this works:
{{ form.cc_date_initial.errors }}{{ form.cc_date_initial }}</p>
{% else %}
{% endif %}
<p>and a revenue goal of
<p>and a revenue goal of
{{ form.target.errors }}${{ form.target }},</p>
{% if form.instance.dollar_per_day %}
<p>If you launch today, when the Book has earned
<p>If you launch today, when the Book has earned
${{ form.revenue.errors }}{{ form.revenue }}, the new Ungluing Date will be <span class="call-to-action">{{ form.instance.cc_date }}</span> and every additional <span class="call-to-action">${{ form.instance.dollar_per_day|floatformat:2|intcomma }}</span> received will advance the Ungluing Date by one day.</p>
<p><input type="submit" value="Calculate" /> another Ungluing Date</p>

View File

@ -1,62 +1,62 @@
<div class="jsmodule">
<h3 class="jsmod-title"><span>FAQs</span></h3>
<div class="jsmod-content">
<ul class="menu level1">
<li class="first parent">
<a href="/faq/"><span>All</span></a>
</li>
<div class="">
<h3 class="jsmod-title"><span>FAQs</span></h3>
<div class="jsmod-content">
<ul class="faq-toplevel-nav vertical menu">
<li class="parent {% if location != 'basics' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'basics' %}"><span>About the site</span></a>
<ul class="menu level2">
<li class="first"><a href="{% url 'faq_sublocation' 'basics' 'howitworks' %}"><span>About Unglue.it</span></a></li>
<li><a href="{% url 'faq_sublocation' 'basics' 'account' %}"><span>Your Account</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'basics' 'company' %}"><span>The Organization</span></a></li>
</ul>
</li>
<li class="parent {% if location != 'unglued_ebooks' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'unglued_ebooks' %}"><span>Unglued Ebooks</span></a>
<ul class="menu level2">
<li class="first"><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'general' %}"><span>General Questions</span></a></li>
<li><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'using' %}"><span>Using Your Unglued Ebook</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'copyright' %}"><span>Ungluing and Copyright</span></a></li>
</ul>
</li>
<li class="first parent">
<a href="/faq/"><span>All</span></a>
</li>
<li class="parent {% if location != 'campaigns' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'campaigns' %}"><span>Campaigns</span></a>
<ul class="menu level2">
<li class="first"><a href="{% url 'faq_sublocation' 'campaigns' 't4u' %}"><span>Thanks-for-Ungluing Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'campaigns' 'b2u' %}"><span>Buy-to-Unglue Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'campaigns' 'supporting' %}"><span>Pledge Campaigns</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'campaigns' 'premiums' %}"><span>Premiums</span></a></li>
</ul>
</li>
<li class="parent {% if location != 'basics' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'basics' %}"><span>About the site</span></a>
<ul class="nested vertical menu">
<li class="first"><a href="{% url 'faq_sublocation' 'basics' 'howitworks' %}"><span>About Unglue.it</span></a></li>
<li><a href="{% url 'faq_sublocation' 'basics' 'account' %}"><span>Your Account</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'basics' 'company' %}"><span>The Organization</span></a></li>
</ul>
</li>
<li class="parent {% if location != 'rightsholders' and 'smashwords' not in request.path %}collapse{% endif %}">
<a href="{% url 'faq_location' 'rightsholders' %}"><span>For Rights Holders</span></a>
<ul class="menu level2">
<li class="first"><a href="{% url 'faq_sublocation' 'rightsholders' 'authorization' %}"><span>Becoming Authorized</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'claiming' %}"><span>Claiming Works</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'campaigns' %}"><span>Running Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'addingmedia' %}"><span>Adding Media</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'publicity' %}"><span>Publicizing Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'funding' %}"><span>Funding</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'conversion' %}"><span>Ebook Conversion</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'rights' %}"><span>Rights</span></a></li>
<li class="last"><a href="{% url 'about_specific' 'smashwords' %}"><span>Smashwords Authors</span></a></li>
</ul>
</li>
<li class="parent">
<a href="{% url 'libraries' %}"><span>For Libraries</span></a>
</li>
<li class="parent">
<a href="{% url 'landing' %}"><span>Start Exploring</span></a>
</li>
</ul>
</div>
</div>
<li class="parent {% if location != 'unglued_ebooks' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'unglued_ebooks' %}"><span>Unglued Ebooks</span></a>
<ul class="nested vertical menu">
<li class="first"><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'general' %}"><span>General Questions</span></a></li>
<li><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'using' %}"><span>Using Your Unglued Ebook</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'unglued_ebooks' 'copyright' %}"><span>Ungluing and Copyright</span></a></li>
</ul>
</li>
<li class="parent {% if location != 'campaigns' %}collapse{% endif %}">
<a href="{% url 'faq_location' 'campaigns' %}"><span>Campaigns</span></a>
<ul class="nested vertical menu">
<li class="first"><a href="{% url 'faq_sublocation' 'campaigns' 't4u' %}"><span>Thanks-for-Ungluing Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'campaigns' 'b2u' %}"><span>Buy-to-Unglue Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'campaigns' 'supporting' %}"><span>Pledge Campaigns</span></a></li>
<li class="last"><a href="{% url 'faq_sublocation' 'campaigns' 'premiums' %}"><span>Premiums</span></a></li>
</ul>
</li>
<li class="parent {% if location != 'rightsholders' and 'smashwords' not in request.path %}collapse{% endif %}">
<a href="{% url 'faq_location' 'rightsholders' %}"><span>For Rights Holders</span></a>
<ul class="nested vertical menu">
<li class="first"><a href="{% url 'faq_sublocation' 'rightsholders' 'authorization' %}"><span>Becoming Authorized</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'claiming' %}"><span>Claiming Works</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'campaigns' %}"><span>Running Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'addingmedia' %}"><span>Adding Media</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'publicity' %}"><span>Publicizing Campaigns</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'funding' %}"><span>Funding</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'conversion' %}"><span>Ebook Conversion</span></a></li>
<li><a href="{% url 'faq_sublocation' 'rightsholders' 'rights' %}"><span>Rights</span></a></li>
<li class="last"><a href="{% url 'about_specific' 'smashwords' %}"><span>Smashwords Authors</span></a></li>
</ul>
</li>
<li class="parent">
<a href="{% url 'libraries' %}"><span>For Libraries</span></a>
</li>
<li class="parent">
<a href="{% url 'landing' %}"><span>Start Exploring</span></a>
</li>
</ul>
</div>
</div>

View File

@ -13,8 +13,11 @@
{% block extra_css %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/home.scss' %}" />
<!--
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/landingpage4.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/searchandbrowse2.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/searchandbrowse2.scss' %}" /> -->
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/book_panel2.scss' %}" />
{% endblock %}
{% block extra_js %}
@ -22,20 +25,19 @@
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<!-- toggle to panelview state instead of listview default -->
<script type="text/javascript">
jQuery(document).ready(function($) {
jQuery(document).ready(function($) {
$('.listview').addClass("panelview").removeClass("listview");
});
});
var $j = jQuery.noConflict();
function put_un_in_cookie2(){
$j.cookie('un', $j('#id_username_main').val(), {path: '/', expires: 90 });
return true;
}
</script>
</script>
<script type="text/javascript" src="/static/js/definitions.js"></script>
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/highlight_signup.js"></script>
<script type="text/javascript" src="/static/js/expand.js"></script>
<meta name="google-site-verification" content="wFZncBw5tNpwRVyR08NZFNr7WXqv5X1BkEga2fpUNOo" />
@ -44,10 +46,10 @@ function put_un_in_cookie2(){
{% block topsection %}
{% include "learn_more.html" %}
{% endblock %}
{% block content %}
<div id="main-container" class="main-container-fl">
<div class="js-main" id="content-block">
<div class="js-main-container" id="content-block">
<div id="js-maincol-fl">
<div id="js-main-container">
<h3 class="featured_books">Today's Featured Free eBook</h3>
@ -68,7 +70,7 @@ function put_un_in_cookie2(){
</div>
</div>
<div class="book-detail-info" style="float:left;">
<div style="width: 520px;float: left;">
<div style="float: left;">
<div class="book-name" style="font-size:larger; margin-bottom:10px"><a href="{% url 'work' featured.id %}">{{ work.title }}</a></div>
<div>
<div class="pubinfo">
@ -78,13 +80,13 @@ function put_un_in_cookie2(){
{% endif %}{% if work.relators.count > 2 %}{% for author in work.relators %}{% if not forloop.first %}, <span>{{ author.name }}</span>{% endif %}{% endfor %}
{% endif %}
</div>
<div class="book-year">
<div class="book-year">
{% if work.last_campaign.publisher %}
<span><a href="{% url 'bypubname_list' work.last_campaign.publisher.name.id %}">{{ work.last_campaign.publisher }}</a></span>
{% endif %}
<span>{{ work.publication_date }}</span>
</div>
<div class="book-description" style="max-height:200px;overflow:scroll"> {{ work.description|safe }}</div>
<div class="book-description" style="max-height:200px;"> {{ work.description|safe }}</div>
</div>
</div>
</div>
@ -95,76 +97,94 @@ function put_un_in_cookie2(){
<div class="spacer"></div>
<h3 class="featured_books">Your Recent Faves</h3>
<div>
{% for work in faves %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'supporter' request.user %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book_container">
{% for work in faves %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'supporter' request.user %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
<a class="more_featured_books_mobile button success" href="{% url 'supporter' request.user %}">See More</a>
</div>
{% endif %}
{% if top_pledge %}
<div class="spacer"></div>
<h3 class="featured_books">Pledge to Make These eBooks Free</h3>
<div>
{% for campaign in top_pledge %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'pledge' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book-list">
<div class="book_container">
{% for campaign in top_pledge %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'pledge' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
</div>
<a class="more_featured_books_mobile button success" href="{% url 'campaign_list' 'pledge' %}">See More</a>
{% endif %}
<div class="spacer"></div>
<h3 class="featured_books">Read These Free Licensed eBooks</h3>
<div>
{% for work in cc_books %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'cc_list' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book-list">
<div class="book_container">
{% for work in cc_books %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'cc_list' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
<a class="button success more_featured_books_mobile" href="{% url 'cc_list' %}">See More</a>
</div>
<div class="spacer"></div>
{% if top_b2u %}
<h3 class="featured_books">Buy and Read These eBooks to Make Them Free</h3>
<div>
{% for campaign in top_b2u %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'b2u' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book-list">
<div class="book_container">
{% for campaign in top_b2u %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'b2u' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
</div>
<a class="more_featured_books_mobile button success" href="{% url 'campaign_list' 'b2u' %}">See More</a>
{% endif %}
<div class="spacer"></div>
{% if top_t4u %}
<h3 class="featured_books">Read These Free eBooks and Thank the Creators</h3>
<div>
{% for campaign in top_t4u %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 't4u' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book-list">
<div class="book_container">
{% for campaign in top_t4u %}
{% with campaign.work as work %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 't4u' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
</div>
<a class="more_featured_books_mobile button success" href="{% url 'campaign_list' 't4u' %}">See More</a>
{% endif %}
<div class="spacer"></div>
<h3 class="featured_books">Read These Unglued eBooks - You've Made Them Free</h3>
<div>
{% for work in unglued_books %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'unglued' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
<div class="book-list">
<div class="book_container">
{% for work in unglued_books %}
{% with work.googlebooks_id as googlebooks_id %}
{% include "book_panel.html" %}
{% endwith %}
{% endfor %}
<a class="more_featured_books" href="{% url 'campaign_list' 'unglued' %}"><i class="fa fa-arrow-circle-o-right fa-3x"></i></a>
</div>
</div>
<a class="more_featured_books_mobile button success" href="{% url 'campaign_list' 'unglued' %}">See More</a>
<div class="spacer"></div>
</div>
<div id="js-rightcol">
<div class="js-rightcol-padd">
@ -189,7 +209,7 @@ function put_un_in_cookie2(){
<label>Password (again):</label>
<input id="id_password2_main" type="password" class="required" name="password2" size="30" />
</div>
<div class="button">
<div class="sidebar_button">
<input type="submit" class="signup" value="Sign Up Now" onclick="this.disabled=true,this.form.submit();" />
</div>
<div class="google_signup" style="padding-bottom: 10px;">
@ -202,32 +222,25 @@ function put_un_in_cookie2(){
</div>
</div>
{% endif %}
<div class="jsmodule">
<h3 class="module-title">Donate!</h3>
<div class="jsmod-content">
<div>Please help support Unglue.it by making a tax-deductible donation to the Free Ebook Foundation.</div>
<form class="askform" method="POST" action="{% url 'newdonation' %}">
<div class="donate_amount">
<label>Amount ($): </label><input id="amount" max="20000.00" min="1.00" name="amount" step="0.01" type="number" value="10.00" class="donate"></div>
<div class="button">
<input name="pledge" type="submit" value="Donate" id="donatesubmit" class="donate" />
</div>
</form>
<div class="jsmodule">
<h3 class="module-title">Donate!</h3>
<div class="jsmod-content">
<div>Please help support Unglue.it by making a tax-deductible donation to the Free Ebook Foundation.</div>
<form class="askform" method="POST" action="{% url 'newdonation' %}">
<div class="donate_amount">
<label>Amount ($): </label><input id="amount" max="20000.00" min="1.00" name="amount" step="0.01" type="number" value="10.00" class="donate"></div>
<div class="sidebar_button">
<input name="pledge" type="submit" value="Donate" id="donatesubmit" class="donate" />
</div>
</form>
</div>
</div>
<div class="jsmodule">
<h3 class="module-title">News</h3>
<div class="jsmodule latest-ungluing">
<h3 class="module-title">Latest Ungluing</h3>
<div class="jsmod-content">
<a href="https://blog.unglue.it/2018/01/24/unglue-it-has-resumed-crowdfunding/">Unglue.it has resumed crowdfunding</a>
</div>
</div>
<div class="jsmodule">
<h3 class="module-title">Latest Ungluing</h3>
<div class="jsmod-content">
<ul class="ungluingwhat">
{% for event in events %}
<ul class="ungluingwhat">
{% for event in events %}
{% comment %}
events are tuples of date, object, and string representing object type
{% endcomment %}
@ -236,22 +249,22 @@ function put_un_in_cookie2(){
{% if event.2 == "pledge" %}
{% if object.user%}
<span class="user-avatar">
<a href="{% url 'supporter' object.user.username %}"><img src="{{ object.user.profile.avatar_url }}" width="43" height="43" title="{{ object.user.username }}" alt="Avatar for {{ object.user.username }}" /></a>
<a href="{% url 'supporter' object.user.username %}"><img src="{{ object.user.profile.avatar_url }}" title="{{ object.user.username }}" alt="Avatar for {{ object.user.username }}" /></a>
</span>
<span class="user-book-info">
<a href="{% url 'supporter' object.user.username %}">{{ object.user.username }}</a><br />
{% if object.campaign.type == 1 %}
pledged to unglue
pledged to unglue
{% elif object.campaign.type == 2 %}
bought a copy of
bought a copy of
{% elif object.campaign.type == 3 %}
supported
supported
{% endif %}<br />
<a class="user-book-name" href="{% url 'work' object.campaign.work_id %}">{{ object.campaign.work.title }}</a>
</span>
{% else %}
<span class="user-avatar">
<img src="/static/images/header/anonuser.png" width="43" height="43" title="Anonymous User" alt="Avatar for Anonymous User" />
<img src="/static/images/header/anonuser.png" title="Anonymous User" alt="Avatar for Anonymous User" />
</span>
<span class="user-book-info">
Anonymous User<br />
@ -261,22 +274,22 @@ function put_un_in_cookie2(){
{% endif %}
{% elif event.2 == "comment" %}
<span class="user-avatar">
<a href="{% url 'supporter' object.user.username %}"><img src="{{ object.user.profile.avatar_url }}" width="43" height="43" title="{{ object.user.username }}" alt="Avatar for {{ object.user.username }}" /></a>
<a href="{% url 'supporter' object.user.username %}"><img src="{{ object.user.profile.avatar_url }}" title="{{ object.user.username }}" alt="Avatar for {{ object.user.username }}" /></a>
</span>
<span class="user-book-info">
<a href="{% url 'supporter' object.user.username %}">{{ object.user.username }}</a><br />
commented on<br />
<a class="user-book-name" href="{% url 'work' object.content_object.id %}?tab=2">{{ object.content_object.title }}</a>
</span>
</span>
{% elif event.2 == "wish" %}
<span class="user-avatar">
<a href="{% url 'supporter' object.wishlist.user.username %}"><img src="{{ object.wishlist.user.profile.avatar_url }}" width="43" height="43" title="{{ object.wishlist.user.username }}" alt="Avatar for {{ object.wishlist.user.username }}" /></a>
<a href="{% url 'supporter' object.wishlist.user.username %}"><img src="{{ object.wishlist.user.profile.avatar_url }}" title="{{ object.wishlist.user.username }}" alt="Avatar for {{ object.wishlist.user.username }}" /></a>
</span>
<span class="user-book-info">
<a href="{% url 'supporter' object.wishlist.user.username %}">{{ object.wishlist.user.username }}</a><br />
faved<br />
<a class="user-book-name" href="{% url 'work' object.work_id %}">{{ object.work.title }}</a>
</span>
</span>
{% endif %}
{% endwith %}
</li>
@ -285,26 +298,13 @@ function put_un_in_cookie2(){
</div>
</div>
<div class="jsmodule">
<h3 class="module-title">Questions?</h3>
<h3 class="module-title">Questions?</h3>
<div id="jsmod-content">
Read our <a href="/faq/">general FAQ</a> or <a href="/faq/rightsholders/">Author/Publisher FAQ</a>.
</div>
</div>
</div>
</div>
<h3 class="featured_books">As seen on</h3>
<ul id="as_seen_on">
<li><a href="http://boingboing.net/2012/06/28/release-a-deadly-monster-a-dr.html"><img alt="boingboing" src="{{ STATIC_URL }}images/press_logos/boingboing_logo.png"></a></li>
<li><a href="http://www.zeit.de/digital/internet/2012-07/unglue-ebook-creative-commons"><img alt="die zeit" src="{{ STATIC_URL }}images/press_logos/die_zeit_logo.png"></a></li>
<li><a href="http://www.huffingtonpost.com/2012/05/21/unglueit-free-ebooks-crowdfunding_n_1532644.html"><img alt="huffington post" src="{{ STATIC_URL }}images/press_logos/huffington_post_logo.png"></a></li>
<li><a href="http://techcrunch.com/2014/05/06/unglue-it-sets-books-free-after-authors-get-paid/"><img alt="techcrunch" src="{{ STATIC_URL }}images/press_logos/techcrunch_logo.png"></a></li>
<li><a href="http://www.thedigitalshift.com/2014/02/ebooks/buy-unglue-ebook-crowdfunding-model-goes-beta/"><img alt="library journal" src="{{ STATIC_URL }}images/press_logos/library_journal_logo.png"></a></li>
<li><a href="http://www.networkworld.com/community/node/85329"><img alt="networkworld" src="{{ STATIC_URL }}images/press_logos/networkworld_logo.png"></a></li>
</ul>
<div class="speech_bubble"><span>For readers its a gold mine of great books they can have a say in bringing to market.</span></div>
</div>
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -16,131 +16,6 @@
</div>
</div>
</div>
<div {%if request.user.is_authenticated or hide_learn_more %}id="user-block-hide" {% endif %}class="user-block-hide learnmore_block ">
<h1 style="text-align: center;padding-top: 1em;width: 70%; line-height: 1.2em;">Find over 10,000 <i>free</i> ebooks here.<br />Help us make more ebooks <i>free</i>!</h1>
<div class="quicktour panelview" >
<div class="panelview panelfront side1" >
<span style="color: #8ac3d7; " class="makeaskgive">MAKE</span>
<div class="qtbutton make"><i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i></div>
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> make ebooks in EPUB, MOBI, and PDF.<br />
<span class="highlight">Ungluers</span> love them for doing it.<br />
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #8dc63f; " class="makeaskgive">GIVE</span>
<a title="Download this work" class="qtbutton qtreadittext"><div class="read_itbutton qtreadit"><span>Read it Now</span></div></a>
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> apply <a href="https://creativecommons.org/">Creative Commons</a> licenses to ebooks.<br />
<span class="highlight">Ungluers</span> read them at home, at a library, anywhere.<br />
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #e18551; " class="makeaskgive">ASK</span>
<input name="pledge" type="submit" value="Say Thank You" class="qtbutton" style="
left: 42px;
">
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> ask downloaders to contribute what they choose.<br />
<span class="highlight">Ungluers</span> say thank you with their support.
</div>
</div>
<div class="quicktour last">
<div class="programlink">
<a href="{% url 'faq_sublocation' 'campaigns' 't4u' %}">"Thanks for Ungluing"</a>
</div>
</div>
<div class="learnmore_row"></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1" >
<span style="color: #8ac3d7; " class="makeaskgive">MAKE</span>
<div class="qtbutton make"><i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i></div>
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> make ebooks in EPUB.<br />
<span class="highlight">Ungluers</span> love them for doing it.<br />
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #e18551; " class="makeaskgive">ASK</span>
<input name="pledge" type="submit" value="Purchase" class="qtbutton" style="
left: 84px;
">
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> set a funding goal and a per-copy price.<br />
<span class="highlight">Ungluers</span> purchase the ebook to advance the campaign.
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #8dc63f; " class="makeaskgive">GIVE</span>
<a title="Download this work" class="qtbutton qtreadittext"><div class="read_itbutton qtreadit"><span>Read it Now</span></div></a>
</div>
<div class="panelview panelback side2" >
When the funding goal is met, <a href="https://creativecommons.org/">Creative Commons</a> licenses are automatically applied.<br />
</div>
</div>
<div class="quicktour last">
<div class="programlink">
<a href="{% url 'faq_sublocation' 'campaigns' 'b2u' %}">"Buy to Unglue"</a>
</div>
</div>
<div class="learnmore_row"></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #e18551; " class="makeaskgive">ASK</span>
<input name="pledge" type="submit" value="Pledge" class="qtbutton" style="
left: 100px;
">
</div>
<div class="panelview panelback side2" >
<span class="highlight">Creators</span> set a funding goal and rewards for supporters.<br />
<span class="highlight">Ungluers</span> pledge to support the campaign.
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1" >
<span style="color: #8ac3d7; " class="makeaskgive">MAKE</span>
<div class="qtbutton make"><i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i>&nbsp;<i class="fa fa-heart-o"></i></div>
</div>
<div class="panelview panelback side2" >
When the campaign succeeds, We collect <span class="highlight">Ungluer</span> pledges.<br />
The ebook is <span class="highlight">created</span> and rewards are distributed.
</div>
</div>
<div class="arrow"><i class="fa fa-arrow-right"></i></div>
<div class="quicktour panelview" >
<div class="panelview panelfront side1">
<span style="color: #8dc63f; " class="makeaskgive">GIVE</span>
<a title="Download this work" class="qtbutton qtreadittext"><div class="read_itbutton qtreadit"><span>Read it Now</span></div></a>
</div>
<div class="panelview panelback side2" >
<a href="https://creativecommons.org/">Creative Commons</a> licenses are applied.<br />
<span class="highlight">Ungluers</span> read them at home, at a library, anywhere.<br />
</div>
</div>
<div class="quicktour last">
<div class="programlink">
<a href="{% url 'faq_sublocation' 'campaigns' 'supporting' %}">"Pledge to Unglue"</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -14,7 +14,6 @@
{% block extra_js %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/import_books.js"></script>
<script type="text/javascript" src="/static/js/counter.js"></script>
@ -233,4 +232,4 @@ function highlightTarget(targetdiv) {
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -12,7 +12,6 @@
<script src="/static/js/slides.min.jquery.js"></script>
<script src="/static/js/slideshow.js"></script>
<script src="/static/js/greenpanel.js"></script>
<!-- toggle to panelview state instead of listview default -->
<script type="text/javascript">
@ -22,7 +21,6 @@
</script>
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/embed.js"></script>
{% endblock %}
@ -84,4 +82,4 @@
</div>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,123 @@
{% load sass_tags %}
<!DOCTYPE html>
<head>
<title>Read {{ work.title }} online at unglue.it</title>
<meta property="og:title" content="{{ work.title }}" />
<meta property="og:type" content="book" />
<meta property="og:url" content="https://unglue.it{% url 'work' work.id %}" />
<meta property="og:image" content="{{ work.cover_image_thumbnail }}" />
<meta property="og:site_name" content="Unglue.it" />
{% for author in work.relators %}
<meta property="book:author" content="{{ author.name }}" />
{% endfor %}
{% if work.first_isbn_13 %}
<meta property="book:isbn" content="{{ work.first_isbn_13 }}" />
{% endif %}
<link type="text/css" rel="stylesheet" href="/static/css/reader/normalize.css" />
<link type="text/css" rel="stylesheet" href="/static/css/reader/main.css" />
<link type="text/css" rel="stylesheet" href="/static/css/reader/popup.css" />
<link type="text/css" rel="stylesheet" href="/static/css/reader/annotations.css" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/read.scss' %}" />
<script src="/static/js/reader/libs/jquery.min.js"></script>
<script src="/static/js/reader/libs/zip.min.js"></script>
<script>
"use strict";
document.onreadystatechange = function () {
if (document.readyState == "complete") {
EPUBJS.filePath = "/static/js/reader/libs/";
EPUBJS.cssPath = window.location.href.replace(window.location.hash, '').replace('index.html', '') + "css/";
// fileStorage.filePath = EPUBJS.filePath;
window.reader = ePubReader("{{url}}", {restore: true});
}
};
</script>
<!-- File Storage -->
<script src="/static/js/reader/libs/localforage.min.js"></script>
<!-- Full Screen -->
<script src="/static/js/reader/libs/screenfull.min.js"></script>
<!-- Render -->
<script src="/static/js/reader/epub.min.js"></script>
<!-- Hooks -->
<script src="/static/js/reader/hooks.min.js"></script>
<!-- Reader -->
<script src="/static/js/reader/reader.min.js"></script>
</head>
{% with work.id as work_id %}
<body>
<div id="sidebar">
<div id="panels">
<input id="searchBox" placeholder="search" type="search">
<a id="show-Search" class="show_view icon-search" data-view="Search">Search</a>
<a id="show-Toc" class="show_view icon-list-1 active" data-view="Toc">TOC</a>
<a id="show-Bookmarks" class="show_view icon-bookmark" data-view="Bookmarks">Bookmarks</a>
<a id="show-Notes" class="show_view icon-edit" data-view="Notes">Notes</a>
</div>
<div id="tocView" class="view">
</div>
<div id="searchView" class="view">
<ul id="searchResults"></ul>
</div>
<div id="bookmarksView" class="view">
<ul id="bookmarks"></ul>
</div>
<div id="notesView" class="view">
<div id="new-note">
<textarea id="note-text"></textarea>
<button id="note-anchor">Anchor</button>
</div>
<ol id="notes"></ol>
</div>
</div>
<div id="main">
<div id="titlebar">
<div id="opener">
<a id="slider" class="icon-menu">Menu</a>
</div>
<div id="metainfo">
<span id="book-title"></span>
<span id="title-seperator">&nbsp;&nbsp;&nbsp;&nbsp;</span>
<span id="chapter-title"></span>
</div>
<div id="title-controls">
<a id="bookmark" class="icon-bookmark-empty">Bookmark</a>
<a id="setting" class="icon-cog">Settings</a>
<a id="fullscreen" class="icon-resize-full">Fullscreen</a>
</div>
</div>
<div id="divider"></div>
<div id="prev" class="arrow"></div>
<div id="viewer"></div>
<div id="next" class="arrow"></div>
<div id="loader"><img src="/static/images/reader/loader.gif"></div>
</div>
<div class="modal md-effect-1" id="settings-modal">
<div class="md-content">
<h3>Settings</h3>
<div>
<p>
<input type="checkbox" id="sidebarReflow" name="sidebarReflow">Reflow text when sidebars are open.
</p>
</div>
<div class="closer icon-cancel-circled"></div>
</div>
</div>
<div class="overlay"></div>
</body>
{% endwith %}

View File

@ -2,7 +2,6 @@
{% block title %}Log in to Unglue.it{% endblock %}
{% block doccontent %}
<div id="lightbox_content">
{% if form.errors %}
{% for error in form.non_field_errors %}
@ -16,7 +15,6 @@ Make sure the username box has your <b>username, not your email</b> -- some brow
<p>
We've sent your book to your Kindle. Happy reading!
</p>
<p>
In the future you can send yourself unglued ebooks with one click. Log in, or sign up, and we'll add your Kindle email to your profile so you never have to enter it again.
</p>
@ -31,14 +29,19 @@ Make sure the username box has your <b>username, not your email</b> -- some brow
<a href="{% url 'libraryauth_password_reset' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}">Forgot</a> your password? <a href="{% url 'registration_register' %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}">Need an account</a>? <a href="/faq/basics/account">Other questions</a>?
<br /><br />
<a class="btn btn-social btn-google-plus" href="{% url 'social:begin' "google-oauth2" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}" ><i class="fa fa-google"></i>Sign in with Google</a>
<a class="btn btn-social btn-yahoo" href="{% url 'social:begin' "yahoo" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}" ><i class="fa fa-yahoo"></i>Sign in with Yahoo!</a>
<div class="google-signup">
<a class="btn btn-social btn-google-plus" href="{% url 'social:begin' "google-oauth2" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}" >
<i class="fa fa-google"></i>
Sign in with Google
</a>
<a class="btn btn-social btn-yahoo" href="{% url 'social:begin' "yahoo" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}{{ request.get_full_path|urlencode}}{% endif %}" >
<i class="fa fa-yahoo"></i>
Sign in with Yahoo!
</a>
</div>
{% else %}
<div>
You are already logged in as <a href="{% url 'supporter' user %}">{{ user.username }}</a>.
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -1,11 +1,10 @@
<!-- login_form.html -->
<form method="post" action="{% url 'superlogin' %}" class="login">{% csrf_token %}
{{ form.username.label_tag }}
{{ form.username.label_tag }}
{{ form.username }}
{{ form.password.label_tag }}
{{ form.password }}
<br />
<input type="submit" name="submit" value="Sign in with Password" />
<input type="submit" name="submit" class="button success float-center" value="Sign in"/>
<input type="hidden" name="next" value="{% if next %}{{ next }}{% else %}/{% endif %}" />
</form>

View File

@ -34,18 +34,15 @@ $j(document).ready(function() {
{% block extra_head %}
<link href="{% sass_src 'scss/documentation2.scss' %}" rel="stylesheet" type="text/css" />
{% block extra_extra_head %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/registration2.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/registration.scss' %}" />
{% endblock %}
{% endblock %}
{% block content %}
<div id="registration">
<div id="login_centerer">
<div id="login">
{% block doccontent %}
{% endblock %}
</div>
</div>
</div>
<div class="spacer"></div>
<div class="registration">
<div class="registration-content login-border">
{% block doccontent %}
{% endblock %}
</div>
</div>
{% endblock %}

View File

@ -1,40 +1,47 @@
{% extends "registration/registration_base.html" %}
{% block title %}Register for an account{% endblock %}
{% block extra_js %}
{{ block.super }}
<script type="text/javascript">
function put_un_in_cookie(){
$j.cookie('un', $j('#id_username').val(), {path: '/', expires: 90 });
return true;
}
function put_un_in_cookie(){
$j.cookie('un', $j('#id_username').val(), {path: '/', expires: 90 });
return true;
}
</script>
{% endblock %}
{% block doccontent %}
{% if not user.is_authenticated %}
<h3>Sign up for a Unglue.it account:</h3>
<form method='post' action='#' class="p_form" onsubmit="return put_un_in_cookie();">{% csrf_token %}
<div>{{ form.username.label }}: {{ form.username.errors }}<br />{{ form.username }}</div>
<div>{{ form.email.label }}: {{ form.email.errors }}<br />{{ form.email }}</div>
<div>{{ form.password1.label }}: {{ form.password1.errors }}<br />{{ form.password1 }}</div>
<div>{{ form.password2.label }}: {{ form.password2.errors }}<br />{{ form.password2 }}</div>
<input type="submit" value="Send activation email" onclick="this.disabled=true,this.form.submit();" />
</form>
<form method='post' action='#' class="p_form" onsubmit="return put_un_in_cookie();">{% csrf_token %}
<div>{{ form.username.label }}: {{ form.username.errors }}<br />{{ form.username }}</div>
<div>{{ form.email.label }}: {{ form.email.errors }}<br />{{ form.email }}</div>
<div>{{ form.password1.label }}: {{ form.password1.errors }}<br />{{ form.password1 }}</div>
<div>{{ form.password2.label }}: {{ form.password2.errors }}<br />{{ form.password2 }}</div>
<input type="submit" class="button success float-center" value="Send activation email" onclick="this.disabled=true,this.form.submit();" />
</form>
<div class="google_signup">
<h3>...or</h3>
<a class="btn btn-social btn-google-plus" href="{% url 'social:begin' "google-oauth2" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}/next/{% endif %}" ><i class="fa fa-google"></i>Sign in with Google</a>
<a class="btn btn-social btn-yahoo" href="{% url 'social:begin' "yahoo" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}/next/{% endif %}" ><i class="fa fa-yahoo"></i>Sign in with Yahoo!</a>
<div class="google-signup">
<span class="linetext-outer"><span class="linetext-inner" >or</span></span>
<a class="btn btn-social btn-google-plus" href="{% url 'social:begin' "google-oauth2" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}/next/{% endif %}" >
<i class="fa fa-google"></i>
Sign in with Google
</a>
<a class="btn btn-social btn-yahoo" href="{% url 'social:begin' "yahoo" %}?next={% if request.GET.next %}{{ request.GET.next|urlencode }}{% else %}/next/{% endif %}" >
<i class="fa fa-yahoo"></i>
Sign in with Yahoo!
</a>
</div>
{% else %}
<div>
You are already logged in as <a href="{% url 'supporter' user %}">{{ user.username }}</a>.
You are already logged in as <a href="{% url 'supporter' user %}">{{ user.username }}</a>.
</div>
{% endif %}
</div>
{% endblock %}

View File

@ -2,18 +2,31 @@
{% block title %}Welcome to Unglue.It{% endblock %}
{% block extra_css %}
<style>
#header #header-search-bar { visibility: hidden; }
</style>
{% endblock %}
{% block doccontent %}
<div id="welcomesearch">
<p>Welcome, {{user.username}}!</p><p id="link-to-next"></p>
<label>Search and add free-licenced books! </label>
<form action="{% url 'search' %}" method="get">
<input type="text" onfocus="imgfocus()" onblur="imgblur(0)" size="25" class="inputbox" name="q" value="{{ q }}">
<input type="submit" class="greenbutton" value="Search">
</form>
</div>
<br />
<div class="welcomealternatives">
Or you can <a href="{% url 'edit_user' %}">change your username</a> &#151; <a href="{% url 'work_list' 'popular' %}">see the site's favorite books</a> &#151; <a href="{% url 'feedback' %}">send us feedback</a> &#151; <a href="{% url 'notification_notice_settings' %}">manage your contact preferences</a>
<div class="registration">
<div class="registration-content">
<h1>Welcome, {{user.username}}!</h1>
<h2>
<label>Search and add free-licenced books! </label>
</h2>
<div id="header-search-bar">
<form action="{% url 'search' %}" method="get">
<input role="search" type="text" placeholder="Search" id="welcomesearch" size="25" onfocus="imgfocus()" onblur="imgblur(15)" class="inputbox" name="q" value="{{ q }}"></input>
<i class="fa fa-search"></i>
</form>
</div>
<br />
<div class="welcomealternatives">
Or you can <a href="{% url 'edit_user' %}">change your username</a> &#151; <a href="{% url 'work_list' 'popular' %}">see the site's favorite books</a> &#151; <a href="{% url 'feedback' %}">send us feedback</a> &#151; <a href="{% url 'notification_notice_settings' %}">manage your contact preferences</a>
</div>
</div>
</div>
{% endblock %}

View File

@ -13,7 +13,6 @@
{% endblock %}
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript">
(function($){

View File

@ -14,7 +14,6 @@
{% block extra_js %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/import_books.js"></script>
<script type="text/javascript" src="/static/js/counter.js"></script>
@ -410,4 +409,4 @@ function highlightTarget(targetdiv) {
</div>
</div>
{% endblock %}
{% endblock %}

View File

@ -14,7 +14,6 @@
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript" src="/static/js/hijax_unglued.js"></script>
<script type="text/javascript" src="/static/js/tabs.js"></script>

View File

@ -5,8 +5,7 @@
{% load lib_acqs %}
{% load purchased %}
{% load sass_tags %}
{% block title %}&#151;
{% block title %}&#151;
{% if work.is_free %}
{{ work.title }} is a Free eBook. {% for fmt in work.formats %}[{{ fmt }}]{% endfor %}
{% else %}
@ -24,520 +23,222 @@
{% endblock %}
{% block extra_css %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/campaign2.scss' %}" />
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/bookview.scss' %}" />
{% if user.is_staff or user in work.last_campaign.managers.all %}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
{{ kwform.media.css }}
{% endif %}
{% endblock %}
{% block extra_js %}
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="/static/js/tabs4.js"></script>
<script type="text/javascript" src="/static/js/widgets.js"></script>
<script type="text/javascript" src="/static/js/counter.js"></script>
<script type="text/javascript" src="/static/js/embed.js"></script>
{% if user.is_staff or user in work.last_campaign.managers.all %}
{{ kwform.media.js }}
{% endif %}
<!-- needed for DeGruyter seed description hack
makes template vars accessible in JS
-->
<script type="text/javascript">
var numWishers = {{ wishers }};
{% if request.user.id in work.last_campaign.supporters %}
var isSupporter = true;
{% else %}
var isSupporter = false;
{% endif %}
</script>
{% endblock %}
{% block topsection %}
{% if work.last_campaign.status == 'ACTIVE' %}
{% if request.user in work.last_campaign.managers.all %}
<div class="launch_top pale">Hi, {{ request.user.username }}. Since you're a manager for this campaign, you can <a href="{% url 'manage_campaign' id=work.last_campaign.id %}">edit this campaign</a>.</div>
{% endif %}
{% elif not work.user_with_rights %}
{% if request.user.rights_holder.all %}
<div class="launch_top pale">Hi, {{ request.user.username }}. Since you're an authorized Unglue.it rights holder, if you own the worldwide electronic rights to this work, you may claim it through the More... tab. Need help? Check out the <a href="{% url 'rightsholders' %}">rights holder tools page</a>.</div>
{% endif %}
{% elif request.user == work.user_with_rights %}
{% if work.last_campaign.status != 'SUCCESSFUL' %}
<div class="launch_top pale">Hi, {{ request.user.username }}. Since you're a rights holder for this work, you can <a href="{% url 'rightsholders' %}">launch a campaign</a>.</div>
{% endif %}
{% endif %}
{% endblock %}
{% block content %}
{% purchased %}
{% lib_acqs %}
{% with work.last_campaign_status as status %}
{% block content %}
{% with work.id as work_id %}
<div id="main-container" itemscope itemtype="http://schema.org/Book">
<div class="js-main">
<div id="js-leftcol">
{% include "explore.html" %}
<div class="wrapper">
<div class="bookImage">
{% if work.uses_google_cover %}
<a href="{{ work.googlebooks_url }}">
<img src="{{ work.cover_image_thumbnail }}" alt="Find {{ work.title }} at Google Books" title="Find {{ work.title }} at Google Books" width="131" height="192" />
</a>
{% else %}
<img itemprop="image" src="{{ work.cover_image_thumbnail }}" alt="{{ work.title }}" title="{{ work.title }}" width="131" height="192" />
{% endif %}
</div>
<div class="bookDescription">
<div class="pubinfo">
<h2 class="book-name" itemprop="name">{{ work.title }}</h2>
<h3 class="book-author">
<span itemprop="author">
<a href="{% url 'search' %}?q={{ work.relators.0.author.name|urlencode }}&amp;ty=au" />
{{ work.relators.0.name }}
</a>
</span>
{% if work.authors.count == 2 %}
and <span itemprop="author"><a href="{% url 'search' %}?q={{ work.relators.1.author.name|urlencode }}&amp;ty=au" />{{ work.relators.1.name }}</a></span>
{% endif %}{% if work.relators.count > 2 %}{% for author in work.relators %}{% if not forloop.first %}, <span itemprop="author"><a href="{% url 'search' %}?q={{ author.author.name|urlencode }}&amp;ty=au" />{{ author.name }}</a></span>{% endif %}{% endfor %}
{% endif %}
</h3>
<h3 class="book-year">
{% if work.last_campaign.publisher %}
<span itemprop="publisher"><a href="{% url 'bypubname_list' work.last_campaign.publisher.name.id %}">{{ work.last_campaign.publisher }}</a></span>
{% endif %}
<span itemprop="datePublished">{{ work.publication_date }}</span>
<meta itemprop="inLanguage" content="work.language" />
<meta itemprop="typicalAgeRange" content="work.age_range" />
</h3>
</div>
<div id="js-maincol">
<div class="js-maincol-inner">
<div id="content-block">
<div class="book-detail">
{% if work.uses_google_cover %}
<div class="book-cover" id="book-detail-img">
<a href="{{ work.googlebooks_url }}">
<img src="{{ work.cover_image_thumbnail }}" alt="Find {{ work.title }} at Google Books" title="Find {{ work.title }} at Google Books" width="131" height="192" /></a>
</div>
{% else %}
<div id="book-detail-img" class="book-cover" >
<img itemprop="image" src="{{ work.cover_image_thumbnail }}" alt="{{ work.title }}" title="{{ work.title }}" width="131" height="192" />
</div>
{% endif %}
<div class="book-detail-info">
<div class="layout">
<h2 class="book-name" itemprop="name">{{ work.title }}</h2>
<div>
<div class="pubinfo">
<h3 class="book-author">
<span itemprop="author"><a href="{% url 'search' %}?q={{ work.relators.0.author.name|urlencode }}&amp;ty=au" >{{ work.relators.0.name }}</a></span>{% if work.authors.count == 2 %}
and <span itemprop="author"><a href="{% url 'search' %}?q={{ work.relators.1.author.name|urlencode }}&amp;ty=au" >{{ work.relators.1.name }}</a></span>
{% endif %}{% if work.relators.count > 2 %}{% for author in work.relators %}{% if not forloop.first %}, <span itemprop="author"><a href="{% url 'search' %}?q={{ author.author.name|urlencode }}&amp;ty=au" >{{ author.name }}</a></span>{% endif %}{% endfor %}
{% endif %}
</h3>
<h3 class="book-year">
{% if work.last_campaign.publisher %}
<span itemprop="publisher"><a href="{% url 'bypubname_list' work.last_campaign.publisher.name.id %}">{{ work.last_campaign.publisher }}</a></span>
{% endif %}
<span itemprop="datePublished">{{ work.publication_date }}</span>
<meta itemprop="inLanguage" content="work.language" />
<meta itemprop="typicalAgeRange" content="work.age_range" />
</h3>
</div>
</div>
</div>
{% if status == 'ACTIVE' %}
{% if work.last_campaign.type != 3 %}
<div class="thermometer" title="{{ work.percent_of_goal }}% of goal">
<div class="cover" style="width: {{ cover_width }}%;">
</div>
<span>{{ work.percent_of_goal }}% of goal</span>
</div>
{% endif %}
<div class="pledged-info noborder">
<div class="campaign-status-info">
{% if work.last_campaign.type == 1 %}
<span>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</span> pledged
{% endif %}
{% if work.last_campaign.type == 2 %}
current ungluing date:
{% endif %}
{% if work.last_campaign.type == 3 %}
<span>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</span> of thanks from
{% endif %}
</div>
<div class="campaign-status-info explainer">
{% if work.last_campaign.type == 1 %}
<span>${{ work.last_campaign.target|floatformat:0|intcomma }}</span> goal
{% endif %}
{% if work.last_campaign.type == 2 %}
<span class="current_cc_date ">{{ work.last_campaign.cc_date|date:"M j, Y" }}</span>
<span class="explanation">After {{ work.last_campaign.cc_date|date:"M j, Y" }} this book will be available for free to anyone, anywhere. Every purchase before then brings that date closer.</span>
{% endif %}
{% if work.last_campaign.type != 3 %}
</div>
<div class="campaign-status-info">
{% endif %}
{% if work.last_campaign.supporters_count == 1 %}
<span>1</span> ungluer
{% else %}
<span>{{ work.last_campaign.supporters_count }}</span> ungluers
{% endif %}
{% if work.last_campaign.type == 3 %}
<br />
{% if work.last_campaign.anon_count == 1 %}
<span>1</span> other
{% else %}
<span>{{ work.last_campaign.anon_count }}</span> others
{% endif %}
{% endif %}
</div>
{% if work.last_campaign.type == 2 %}
<div class="campaign-status-info">
{% if work.lib_acqs.count == 1 %}
<span>1</span> copy in a library
{% else %}
<span>{{ work.lib_acqs.count }}</span> in libraries
{% endif %}
</div>
{% endif %}
{% if work.last_campaign.type != 3 %}
<div class="campaign-status-info explainer">
{% if work.last_campaign.type == 1 %}
<span>{{ work.last_campaign.countdown }}</span> to go
{% else %}
<span>${{ work.last_campaign.left|floatformat:0|intcomma }}</span> to go
<span class="explanation">${{ work.last_campaign.left|floatformat:0|intcomma }} is the amount it would take to make this ebook free to the world tomorrow.</span>
{% endif %}
</div>
{% endif %}
</div>
{% else %}
{% if status == 'SUCCESSFUL' %}
<div class="thermometer successful">
This campaign succeeded on {{ work.last_campaign.success_date|date:"M j, Y" }}.
</div>
<div class="pledged-info noborder">
<div class="campaign-status-info">
{% if work.last_campaign.supporters_count == 1 %}
<span>1</span> ungluer
{% else %}
<span>{{ work.last_campaign.supporters_count }}</span> ungluers
{% endif %}
</div>
<div class="campaign-status-info">
<span>${{ work.last_campaign.current_total|floatformat:0|intcomma }}</span> raised
</div>
<div class="campaign-status-info">
<span>${{ work.last_campaign.target|floatformat:0|intcomma }}</span> goal
</div>
<div class="campaign-status-info">
<span>Unglued!</span>
</div>
</div>
{% endif %}
<div class="pledged-info">
{% if wishers == 1 %}
1 Ungluer has
{% else %}
{{ wishers }} Ungluers have
{% endif %} Faved this Work
</div>
{% endif %}
<div class="find-book">
<label>Learn more at...</label>
<div class="find-link">
{% if work.googlebooks_id %}
<a id="find-google" href="{{ work.googlebooks_url }}"><img src="/static/images/supporter_icons/googlebooks_square.png" title="Find on Google Books" alt="Find on Google Books" /></a>
{% endif %}
{% if work.first_oclc %}
<a rel="nofollow" id="find-oclc" href="https://www.worldcat.org/oclc/{{ work.first_oclc }}"><img src="/static/images/supporter_icons/worldcat_square.png" title="Find on Worldcat" alt="Find on Worldcat" /></a>
{% endif %}
<a rel="nofollow" class="find-openlibrary" href="{% url 'work_openlibrary' work_id %}"><img src="/static/images/supporter_icons/openlibrary_square.png" title="Find on OpenLibrary" alt="Find on OpenLibrary" /></a>
<a rel="nofollow" class="find-goodreads" href="{% url 'work_goodreads' work_id %}"><img src="/static/images/supporter_icons/goodreads_square.png" title="Find on GoodReads" alt="Find on GoodReads" /></a>
<a rel="nofollow" class="find-librarything" href="{% url 'work_librarything' work_id %}"><img src="/static/images/supporter_icons/librarything_square.png" title="Find on LibraryThing" alt="Find on LibraryThing" /></a>
</div>
</div>
<div class="btn_wishlist" id="wishlist_actions">
{% if request.user.is_anonymous %}
<div class="create-account">
<span title="{% url 'work' work_id %}">Login to Fave</span>
</div>
{% elif request.user.id in work.last_campaign.supporters %}
<div class="add-wishlist">
<span class="on-wishlist">Faved!</span>
</div>
{% elif work in request.user.wishlist.works.all %}
<div class="remove-wishlist-workpage">
<span id="w{{ work_id }}">Remove from My Faves</span>
</div>
{% else %}
<div class="add-wishlist">
<span class="work_id" id="w{{ work_id }}">Add to My Faves</span>
</div>
{% endif %}
</div>
</div>
</div>
{% get_comment_count for work as comment_count %}
{% if action == 'editions' %}
<div class="content-block-heading" id="tabs">
<ul class="tabs">
<li class="tabs1"><a href="{% url 'work' work.id %}?tab=1">{% if status == 'ACTIVE' %}Campaign{% else %}Description{% endif %}</a></li>
<li class="tabs2"><a href="{% url 'work' work.id %}?tab=2">Comments {% if comment_count > 0 %}({{ comment_count }}){% endif %}</a></li>
<li class="tabs3" id="supporters"><a href="{% url 'work' work.id %}?tab=3">Ungluers {% if wishers > 0 %}<br />({{ wishers }}){% endif %}</a></li>
<li class="tabs4 active"><a href="#">Editions</a></li>
</ul>
</div>
{% else %}
<div class="content-block-heading" id="tabs">
<ul class="tabs">
<li class="tabs1 {% if activetab == '1' %}active{% endif %}"><a href="#">{% if status == 'ACTIVE' %}Campaign{% else %}Description{% endif %}</a></li>
<li class="tabs2 {% if activetab == '2' %}active{% endif %}"><a href="#">Comments {% if comment_count > 0 %}({{ comment_count }}){% endif %}</a></li>
<li class="tabs3 {% if activetab == '3' %}active{% endif %}" id="supporters"><a href="#">Ungluers {% if wishers > 0 %}<br />({{ wishers }}){% endif %}</a></li>
<li class="tabs4 {% if activetab == '4' %}active{% endif %}"><a href="#">More...</a></li>
</ul>
</div>
{% endif %}
<div id="content-block-content">
<div id="tabs-1" class="tabs {% if activetab == '1' %}active{% endif %}">
<div class="tabs-content">
<div itemprop="description">
{% if status == 'ACTIVE' %}
{% if work.last_campaign.type != 3 %}
{{ work.last_campaign.description|safe }}
{% else %}
{{ work.description|safe }}
{% endif %}
{% elif work.description %}
{{ work.description|safe }}
{% else %}
{{ work.last_campaign.description|safe }}
{% endif %}
</div>
<div>
{% for work_rel in work.works_related_to.all %}
{% if work_rel.from_work.language != 'xx' and work.language != 'xx' %}
<p>
This work is a {{ work_rel.relation }} of <a href="{% url 'work' work_rel.from_work.id %}">{{ work_rel.from_work }}</a>.
</p>
{% endif %}
{% endfor %}
{% for work_rel in work.works_related_from.all %}
{% if work.language != 'xx' and work_rel.to_work.language != 'xx' %}
<p>
<a href="{% url 'work' work_rel.to_work.id %}">{{ work_rel.to_work }}</a> is a {{ work_rel.relation }} of this work.
</p>
{% endif %}
{% endfor %}
{% if work.doab %}
<p>
This book is included in <a href="http://www.doabooks.org/doab?func=search&amp;query=rid%3A{{ work.doab }}">DOAB</a>.
</p>
{% endif %}
{% if work.gtbg %}
<p>
This book is included in <a href="https://www.gutenberg.org/ebooks/{{ work.gtbg }}">Project Gutenberg</a>.
</p>
{% endif %}
</div>
</div>
</div>
<div id="tabs-2" class="tabs {% if activetab == '2' %}active{% endif %}">
<h3>Why {% if work.ebooks.all %}read{% else %}unglue{% endif %} this book? Have your say.</h3>
<div class="tabs-content">
{% render_comment_list for work %}
{% if user.is_authenticated %}
{% render_comment_form for work %}
{% else %}
<p>You must be <a href="{% url 'superlogin' %}?next={{ request.get_full_path|urlencode }}">logged in</a> to comment.</p>
{% endif %}
</div>
</div>
<div id="tabs-3" class="tabs {% if activetab == '3' %}active{% endif %}">
<div class="tabs-content">
{% if request.user.is_staff or request.user in work.last_campaign.managers.all %}
<form id="contact_form" method="POST" action="#" >
{% csrf_token %}
<input type="hidden" name="work" value="{{ work.id }}" />
{% for wish in work.wishes.all reversed %}
{% with wish.wishlist.user as supporter %}
<div class="work_supporter_wide">
<a href="{% url 'supporter' supporter %}">
<span class="work_supporter_avatar">
<img class="user-avatar" src="{{ supporter.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ supporter }}" title="{{ supporter }}" />
</span>
</a>
<div class="show_supporter_contact_form" >
<img src="/static/images/icons/email.png" alt="email" title="contact supporter" />
</div>
<div class="info_for_managers">
{{ supporter }}<br />
Wished: {{ wish.created }}<br />
{% if supporter.id in work.last_campaign.supporters %}Pledged!</br />{% endif %}
{% if supporter in work.last_campaign.ungluers.all %}Supported!</br />{% endif %}
</div>
</div>
<div class="supporter_contact_form" ></div>
<input class="supporter_contact_form" type="submit" name="msg_{{supporter.id}}" value="Send Message to {{ supporter.username }}" />
{% endwith %}
{% endfor %}
</form>
{% else %}
{% for wish in work.wishes.all reversed %}
{% with wish.wishlist.user as supporter %}
<div class="work_supporter_nocomment" itemscope itemtype="http://schema.org/Person">
<a itemprop="url" href="{% url 'supporter' supporter %}">
<span class="work_supporter_avatar">
<img class="user-avatar" src="{{ supporter.profile.avatar_url }}" height="50" width="50" alt="Avatar for {{ supporter }}" title="{{ supporter }}" />
</span>
<span class="work_supporter_name">{{ supporter }}</span>
</a>
</div>
{% endwith %}
{% endfor %}
{% endif %}
</div>
</div>
<div id="tabs-4" class="tabs {% if activetab == '4' %}active{% endif %}">
<div class="tabs-content">
{% if action == 'display' %}
{% if status == 'ACTIVE' %}
{% if work.last_campaign.type == 1 %}
<h3 class="tabcontent-title">A campaign is running to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) if ungluers can join together to raise ${{ work.last_campaign.target|floatformat:0|intcomma }} by {{ work.last_campaign.deadline }}.
You can help!</p>
{% endif %}
{% if work.last_campaign.type == 2 %}
<h3 class="tabcontent-title">A Buy-to-Unglue Campaign is running to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) on {{ work.last_campaign.cc_date }}. For every copy that ungluers purchase, that date gets sooner. ${{ work.last_campaign.left|floatformat:0|intcomma }} of sales will unglue the book <i>TODAY</i>.
You can help!</p>
{% endif %}
{% if work.last_campaign.type == 3 %}
<h3 class="tabcontent-title">A Thanks-for-Ungluing Campaign is running to reward the creators of <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has released <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) .
You can help us say "Thank You!" so that other creators will do the same.</p>
{% endif %}
<h4>Campaign details: the fine print</h4>
{{ work.last_campaign.details|safe }}
{% endif %}
{% if status == 'SUCCESSFUL' %}
<h3 class="tabcontent-title">A campaign has succeeded to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) thanks to the efforts of ungluers like you.</p>
<h4>Campaign details: the fine print</h4>
{{ work.last_campaign.details|safe }}
{% endif %}
{% if status != 'ACTIVE' and status != 'SUCCESSFUL' %}
<h4> Rights Information </h4>
{% if claimstatus == 'one_active' %}
<p>This work has been claimed by {{ rights_holder_name }}.</p>
{% else %}
{% if claimstatus == 'disputed' %}
<p>Rights claims are pending.</p>
{% else %}
{% if claimstatus == 'one_pending' %}
<p>A claim for this work by {{ rights_holder_name }} is pending.</p>
{% else %}
{% if request.user.rights_holder.all.count %}
Is this work yours? Claim it: <br /><br />
<form method="POST" action="{% url 'claim' %}">
{% csrf_token %}
{{ claimform.user }}
{{ claimform.work }}
{{ claimform.rights_holder }}
<input type="submit" name="submit" value="Claim" />
</form><br />
{% else %}
Are you the author or publisher of this work? If so, you can claim it as yours by <a href="{% url 'rightsholders' %}">registering as an Unglue.it rights holder</a>.
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% if work.is_free %}
<h4>Downloads</h4>
<div class="pledged-info">
This work has been downloaded {{ work.download_count }} times via unglue.it ebook links.
<ol>
{% for ebook in work.ebooks.all %}
<li>{{ ebook.download_count }} - {{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}({{ ebook.rights }}) at {{ ebook.provider }}. </li>
{% endfor %}
</ol>
</div>
{% if user.is_staff %}
<p>
<a href="{% url 'feature' work.id %}">Feature this work today.</a>
</p>
{% endif %}
{% endif %}
{% if user.is_staff %}
<h4>Related Works</h4>
<div><a href="{% url 'merge' work_id %}">Merge other works into this one</a></div>
{% endif %}
<h4>Keywords</h4>
{% if work.subjects.all.count > 0 %}
<ul id="kw_list">
{% for subject in work.subjects.all %}
<li itemprop="keywords">{{ subject.name }}
{% if user.is_staff or user in work.last_campaign.managers.all %}
<span class="deletebutton" data="{{ subject.name }}">x</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
No keywords yet.
<ul id="kw_list"></ul>
<div itemprop="description">
{% if status == 'ACTIVE' %}
{% if work.last_campaign.type != 3 %}
{{ work.last_campaign.description|safe }}
{% else %}
{{ work.description|safe }}
{% endif %}
{% elif work.description %}
{{ work.description|safe }}
{% else %}
{{ work.last_campaign.description|safe }}
{% endif %}
{% endif %}
{% if user_can_edit_work %}
<form method="POST" id="kw_add_form">{% csrf_token %}
{{ kwform.add_kw }}<input type="hidden" name="kw_add" value="true"> <input type="submit" name="kw_add_fake" value="add keyword" id="kw_add_form_submit" />
</form>
{% endif %}
{% endif %}
{% with doi=work.doi http_id=work.http_id %}
{% if doi or http_id %}
<h4>Links</h4>
{% if doi %}
DOI: <a href="https://doi.org/{{ doi }}">{{ doi }}</a><br />
{% endif %}
{% if http_id %}
web: <a href="{{ http_id }}">{{ http_id }}</a><br />
{% endif %}
{% endif %}
{% endwith %}
<h4>Editions</h4>
{% if alert %}
<div class="yikes"><br />{{ alert }}</div>
{% endif %}
{% if user_can_edit_work %}
<div><a href="{% url 'new_edition' work_id edition.id %}">Create a new edition for this work</a><br /><br /></div>
{% endif %}
{% if action == 'editions' %}
{% include 'split.html' %}
<div class="description-more-content">
{% if action == 'display' %}
{% if status == 'ACTIVE' %}
{% if work.last_campaign.type == 1 %}
<h3 class="tabcontent-title">A campaign is running to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) if ungluers can join together to raise ${{ work.last_campaign.target|floatformat:0|intcomma }} by {{ work.last_campaign.deadline }}.
You can help!</p>
{% endif %}
{% if work.last_campaign.type == 2 %}
<h3 class="tabcontent-title">A Buy-to-Unglue Campaign is running to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) on {{ work.last_campaign.cc_date }}. For every copy that ungluers purchase, that date gets sooner. ${{ work.last_campaign.left|floatformat:0|intcomma }} of sales will unglue the book <i>TODAY</i>.
You can help!</p>
{% endif %}
{% if work.last_campaign.type == 3 %}
<h3 class="tabcontent-title">A Thanks-for-Ungluing Campaign is running to reward the creators of <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has released <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) .
You can help us say "Thank You!" so that other creators will do the same.</p>
{% endif %}
<h4>Campaign details: the fine print</h4>
{{ work.last_campaign.details|safe }}
{% endif %}
{% if status == 'SUCCESSFUL' %}
<h3 class="tabcontent-title">A campaign has succeeded to unglue <i>{{work.title}}</i>!</h3>
<p>The rights holder, {% for claim in work.claim.all %}
{% if claim.status == 'active' %}
{{ claim.rights_holder.rights_holder_name }}
{% endif %}
{% endfor %}
, has agreed to release <i>{{work.title}}</i> to the world as a Creative Commons licensed ebook (<a href="{{ work.last_campaign.license_url }}">{{ work.last_campaign.license }}</a>) thanks to the efforts of ungluers like you.</p>
<h4>Campaign details: the fine print</h4>
{{ work.last_campaign.details|safe }}
{% endif %}
{% if status != 'ACTIVE' and status != 'SUCCESSFUL' %}
<h4> Rights Information </h4>
{% if claimstatus == 'one_active' %}
<p>This work has been claimed by {{ rights_holder_name }}.</p>
{% else %}
{% if claimstatus == 'disputed' %}
<p>Rights claims are pending.</p>
{% else %}
{% if claimstatus == 'one_pending' %}
<p>A claim for this work by {{ rights_holder_name }} is pending.</p>
{% else %}
{% if request.user.rights_holder.all.count %}
Is this work yours? Claim it: <br /><br />
<form method="GET" action="{% url 'claim' %}">
{% csrf_token %}
{{ claimform.user }}
{{ claimform.work }}
{{ claimform.rights_holder }}
<input type="submit" name="submit" value="Claim" />
</form><br />
{% else %}
{% with work.preferred_edition as edition %}
{% include 'edition_display.html' %}
{% endwith %}
{% if not campaign %}
{% for edition in editions %}
{% if edition != work.preferred_edition %}
{% include 'edition_display.html' %}
{% endif %}
{% endfor %}
{% endif %}
<div><a href="{% url 'work_editions' work_id %}">All editions for this work.</a></div>
Are you the author or publisher of this work? If so, you can claim it as yours by <a href="{% url 'rightsholders' %}">registering as an Unglue.it rights holder</a>.
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{% endif %}
{% endif %}
{% if work.is_free %}
<h4>Downloads</h4>
<div class="pledged-info">
This work has been downloaded {{ work.download_count }} times via unglue.it ebook links.
<ol>
{% for ebook in work.ebooks.all %}
<li>{{ ebook.download_count }} - {{ ebook.format }} {% if ebook.version_label %} ({{ ebook.version_label }}) {% endif %}({{ ebook.rights }}) at {{ ebook.provider }}. </li>
{% endfor %}
</ol>
</div>
</div>
{% if user.is_staff %}
<p>
<a href="{% url 'feature' work.id %}">Feature this work today.</a>
</p>
{% endif %}
{% endif %}
{% if user.is_staff %}
<h4>Related Works</h4>
<div><a href="{% url 'merge' work_id %}">Merge other works into this one</a></div>
{% endif %}
{% endif %}
</div>
</div>
<div id="js-rightcol">
{% include 'work_action.html' %}
</div>
<div class="bookSidebar">
{% if has_online_book %}
<div class="bookRead">
<a href="{% url 'read' work_id %}">
<button class="button expanded success">Read</button>
</a>
</div>
{% endif %}
<div class="bookDownload">
<a href="{% url 'download' work_id %}">
<button class="button expanded success">Download</button>
</a>
</div>
<div class="bookDonate">
<a href="{% url 'download' work_id %}">
<button class="button expanded success">Donate</button>
</a>
</div>
<div class="book-sidebar-item">
<div class="btn_wishlist" id="wishlist_actions">
{% if request.user.is_anonymous %}
<div class="create-account">
<span title="{% url 'work' work_id %}">Login to Fave</span>
</div>
{% elif request.user.id in work.last_campaign.supporters %}
<div class="add-wishlist">
<span class="on-wishlist">Faved!</span>
</div>
{% elif work in request.user.wishlist.works.all %}
<div class="remove-wishlist-workpage">
<span id="w{{ work_id }}">Remove from My Faves</span>
</div>
{% else %}
<div class="add-wishlist">
<span class="work_id" id="w{{ work_id }}">Add to My Faves</span>
</div>
{% endif %}
</div>
</div>
<div class="book-sidebar-item">
<a rel="nofollow" class="find-goodreads" href="{% url 'work_goodreads' work_id %}">
<img src="/static/images/supporter_icons/goodreads_square.png" title="Find on GoodReads" alt="Find on GoodReads" />
<span>GoodReads</span>
</a>
</div>
<div class="book-sidebar-item">
<a rel="nofollow" class="find-librarything" href="{% url 'work_librarything' work_id %}">
<img src="/static/images/supporter_icons/librarything_square.png" title="Find on LibraryThing" alt="Find on LibraryThing" />
<span>LibraryThing</span>
</a>
</div>
</div>
<div class="bookComments">
<h2>Comments</h2>
{% render_comment_list for work %}
{% if user.is_authenticated %}
{% render_comment_form for work %}
{% else %}
<p>You must be <a href="{% url 'superlogin' %}?next={{ request.get_full_path|urlencode }}">logged in</a> to comment.</p>
{% endif %}
</div>
</div>
{% endwith %}
{% endwith %}
{% endblock %}

View File

@ -14,7 +14,6 @@
{% block extra_head %}
<script type="text/javascript" src="/static/js/wishlist.js"></script>
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
<script type="text/javascript" src="/static/js/toggle.js"></script>
<script type="text/javascript" src="/static/js/tabs.js"></script>
{% endblock %}

View File

@ -90,6 +90,7 @@ urlpatterns = [
url(r"^work/(?P<work_id>\d+)/librarything/$", views.work_librarything, name="work_librarything"),
url(r"^work/(?P<work_id>\d+)/goodreads/$", views.work_goodreads, name="work_goodreads"),
url(r"^work/(?P<work_id>\d+)/openlibrary/$", views.work_openlibrary, name="work_openlibrary"),
url(r"^read/(?P<work_id>\d+)/$", views.read, name="read"),
url(r"^new_edition/(?P<work_id>)(?P<edition_id>)$", views.edit_edition, name="new_edition"),
url(r"^new_edition/(?P<work_id>\d*)/(?P<edition_id>\d*)$", views.edit_edition, name="new_edition"),
url(r"^manage_ebooks/(?P<edition_id>\d*)$", views.manage_ebooks, name="manage_ebooks"),
@ -151,4 +152,4 @@ if settings.DEBUG:
url(r"^goodreads/$", login_required(views.GoodreadsDisplayView.as_view()), name="goodreads_display"),
url(r"^goodreads/clear_wishlist/$", views.clear_wishlist, name="clear_wishlist"),
url(r"^celery/clear/$", views.clear_celery_tasks, name="clear_celery_tasks"),
]
]

View File

@ -297,6 +297,18 @@ def stub(request):
def acks(request, work):
return render(request, 'front_matter.html', {'campaign': work.last_campaign()})
def read(request, work_id):
work = safe_get_work(work_id)
try:
ebook_id = work.first_epub().id
url = get_object_or_404(models.Ebook, id=ebook_id).url
except (ValueError, AttributeError):
raise Http404
return render(request, 'read.html', {
'work': work,
'url': url,
})
def work(request, work_id, action='display'):
work = safe_get_work(work_id)
alert = ''
@ -410,7 +422,8 @@ def work(request, work_id, action='display'):
'cover_width': cover_width_number,
'action': action,
'formset': formset,
'kwform': SubjectSelectForm()
'kwform': SubjectSelectForm(),
'has_online_book': work.first_epub() != None,
})
def edition_uploads(request, edition_id):

View File

@ -0,0 +1,46 @@
# Deploying Regluit to Production
The current provisioning setup uses [Ansible](https://www.ansible.com/resources/get-started) to deploy code to production servers.
## Pre-requisites
Before attempting to deploy, ensure you have done the following:
1. Install `ansible` on your local machine
1. Obtain the `ansible-vault` password and save it to a file
1. Set the path to the `ansible-vault` file via environment variable e.g. `export NSIBLE_VAULT_PASSWORD_FILE=[path]`
1. Create/obtain the secret key needed to SSH into the server
1. (optional) Add the secret key to your ssh agent
```
$ ssh-agent bash
$ ssh-add /path/to/secret.pem
```
## Deploy
Deploying is as simple as running the `setup-prod` ansible playbook.
Navigate to the `provisioning/` directory and run the following:
```
$ ansible-playbook -i hosts setup-prod.yml
```
If you successfully completed all the pre-requisite steps, the playbook should begin running through deploy tasks and finally restart apache.
## Additional Configuration
### Variables and Secrets
The necessary variables are pulled from `provisioning/group_vars/production/vars.yml` which in turn pulls certain secret values from `vault.yml`.
The variables are split into two files to still allow for searching references in playbook tasks.
To add or view secret values, you must decrypt the file first: `$ ansible-vault decrypt vault.yml` however **always remember to encrypt secret files before pushing to git**. This is done in a similar manner: `$ ansible-vault encrypt vault.yml`.
Ansible also allows for overriding variables from the command line when running playbooks.
This is useful for ad-hoc playbook runs without editing var files.
For example, deploying code from another branch can be done as so:
`$ ansible-playbook -i hosts setup-prod.yml -e git_branch=mybranch`
### Inventory and Groups
Currently we are using a static inventory file `hosts` to define target server hosts and groups.
This means that the `hosts` file must be manually updated to reflect things such as DNS changes or additional hosts being added.
In the future, the static inventory file may be replaced with a dynamic inventory solution, such as ansible's [ec2 inventory script](http://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html#example-aws-ec2-external-inventory-script)
One important aspect of the `hosts` file is that it defines the groups which a host or hosts are a part of.
Currently, there is only one prod host called `regluit-prod` which is a member of the `production` group.
Both of these designations are important, as the `setup-prod` playbook specifically targets the `regluit-prod` host, and only that host will inherit the variables in `group_vars/production/`.

View File

@ -0,0 +1,58 @@
---
### Variables for Regluit Production Server ###
### Sensitive vars are references to actual values in vault.yml ###
### Use ansible-vault view vault.yml to see the secret values ###
project_path: "/opt/regluit"
django_settings_module: "regluit.settings.prod"
virtualenv_name: "venv"
user_name: "ubuntu"
server_name: "m.unglue.it"
wsgi_home: "/opt/regluit/venv"
wsgi_python_path: "/opt/regluit/venv/bin/python"
git_repo: "https://github.com/EbookFoundation/regluit.git"
git_branch: "master"
### Variables in settings.prod.py ###
mysql_db_name: "{{ vault_mysql_db_name }}"
mysql_db_user: "{{ vault_mysql_db_user }}"
mysql_db_pass: "{{ vault_mysql_db_pass }}"
mysql_db_host: "{{ vault_mysql_db_host }}"
mysql_db_port: ""
email_host: "{{ vault_email_host }}"
email_port: 465
default_from_email: "notices@gluejar.com"
broker_transport: "redis"
broker_host: "127.0.0.1"
broker_port: 6379
broker_vhost: "0"
### Variables in common.py ###
common_keys:
booxtream_api_key: "{{ vault_booxtream_api_key }}"
booxtream_api_user: "{{ vault_booxtream_api_user }}"
dropbox_key: "{{ vault_dropbox_key }}"
github_public_token: "{{ vault_github_public_token }}"
mailchimp_api_key: "{{ vault_mailchimp_api_key }}"
mailchimp_news_id: "{{ vault_mailchimp_news_id }}"
mobigen_url: "{{ vault_mobigen_url }}"
mobigen_user_id: "{{ vault_mobigen_user_id }}"
mobigen_password: "{{ vault_mobigen_password }}"
### Variables in host.py ###
host_keys:
secret_key: '{{ vault_secret_key }}'
google_books_api_key: "{{ vault_google_books_api_key }}"
goodreads_api_key: "{{ vault_goodreads_api_key }}"
goodreads_api_secret: "{{ vault_goodreads_api_secret }}"
email_host_user: '{{ vault_email_host_user }}'
email_host_password: '{{ vault_email_host_password }}'
social_auth_twitter_key: '{{ vault_social_auth_twitter_key }}'
social_auth_twitter_secret: '{{ vault_social_auth_twitter_secret }}'
social_auth_facebook_key: '{{ vault_social_auth_facebook_key }}'
social_auth_facebook_secret: '{{ vault_social_auth_facebook_secret }}'
social_auth_google_oauth2_key: '{{ vault_social_auth_google_oauth2_key }}'
social_auth_google_oauth2_secret: '{{ vault_social_auth_google_oauth2_secret }}'
aws_access_key_id: '{{ vault_aws_access_key_id }}'
aws_secret_access_key: '{{ vault_aws_secret_access_key }}'
aws_storage_bucket_name: '{{ vault_aws_storage_bucket_name }}'

View File

@ -0,0 +1,90 @@
$ANSIBLE_VAULT;1.1;AES256
35613232373661333630323135393138313263623531323030656532643831313832373766393635
3737383265653238663165613563396162613961353532320a363562386230383432646265323563
61313039646366633965653136353264663236356333653265386336386437343832386131333362
3432663165313436390a356633616663383135393232613833663433376239366666336532353066
66306530333030366339636232333164346136393166636434343130646164316135306633363933
37316434376238363963636237393932343065633737383139366465306231323431393061663632
62323863633466613134393862633238623766616139653361653965663766363837376537646164
32366363336262633437333931363130333463333439346566313631633666333139623335393337
38373931643833636532353762376562346530313931343335663463653139323135633161383861
65656462396333646437306265303934306538316537383462303238346665366135656662616532
62306534303233356130356565323034396337383336386238643836303839393031613338656434
62633363663961633837643535663737323631636238393063306236666261306432616338643761
64336364656539306363336461353962333766316137623965633962663066326262316635636530
66646163386134363036386463363332333365396661313138666538383334626266633737303533
65316433383136613063616565633934633230666561663433346564323462396531623133343538
34613233373134323831613365383266363565313632383866373330333032646261316433663539
61363966343366306166393162343834323663616632663761343266663138373164346534343837
66616131323638386532376461336231313238333463303533613830646535633666386463393037
35313562326139616438396633383265383361316262363535323934303837306631386130386637
38313636613963373038646536333466393031613835376639363461383837343731646430343930
30373130376231383837306539633934643030616563386166643865636361643932623031323439
62623364373665353934366633303133343337306139373033313032613261393761363235376135
65356661313361356466353761336239656166356533636461663832613766363736303961666463
65346662346361323032653230626630356336353832656565363963633561343163626266653631
66626239393533653664353438323331616531333438356530653664376561346134626430643964
35393437663861373164303039333138643337653035643761316236313366616563666136666365
32396535663837626239626136393466653534613630316636323932376133376462323730613731
64393039373636353536313036363064633831323334383930663164323539656161613932656364
64636565636136343063626438623639386635306436383432313333376361393035653436353332
64623161316133663166336363343437393962633834333065396433313832333362326639363336
31633333393563306436646464313561643932393632613762643765333835323463303431383133
37653431366661653833623561343637343631616366623165656430396638353638346632326133
31333237336531386239643161623634656334336565646463653763363735653035653334626431
65656361343437316132323733303136623961313030663638656366653836376530393765643133
66306130343331353165643836613339306662393861656132626530626438333439386239396434
64613464646337393866306365333632316565383430303331353533623366373832666336616336
37313961393237363433396333626631643363666366633732386334353062333639333463613035
66306231303331306531636534313036646362336337333964353237396464353138663531346133
66613433326434363138326131383836636330343739336366623364643062633433613766386639
37393562396239633933373735313661316531366662346362313162326233366438653565656531
66323138383834666463313232623535643139336230336664653739386161316466653965653236
64653730623332326239646236636539643435373835333130666133623764343037363663366538
35643130313162376435363336383563363666353366303634663735393632366439373461393737
36353764613834613730376261356566626665396133396364383762633661386238616134633831
61613466633639656662333138396338303630643961353939326462373661356162356534383133
65393739643061356330366535616461326464613332346233616538633439373133323562343363
34343437633236333638366263616235356634613262396562623535383538306430643932353766
39623465376165343839326332623634303431613964646232373738323434313632376336393561
39653065633735326137386539323531656337396339363865393034336131663163646338363733
33356165306661343966373463643034383564313637353339653562663238306233356137383266
30303263303864396430366438613039383436396139343838316364323236356431383831383333
66373762396539636435303334313461663066323062623433356637366564336333346264636530
36646564643331343830363563383231636336366437333064333666616234376637343330306261
62663461303134336531623133363261643863383130373561396665643463613239653535663664
65383164313735366532666461323033313562616539363938333131623066623435616438383563
36313236633131356264346239376135376663303035363835393262666264323033353562366535
64363834363734613635613836623433616239613530623434383061616331656431616438653765
39633764656365396232313062333636376463396466376134366266343536336563626237616666
62346565326138343534303030313539396233656232376561643662343533383464656662653736
64653661666332316265396161646435643566336463393639663063373664633561386630633764
64636633336266646264383834633634636633386330626461336463316334386665366137666233
31643537646331653065336236303730316166393138633765333931646539666466643161353935
66613632643037653333366465353831643437663861623361343066336135666164343661313862
61613737396535363362386238333366396135353065303231313435393434623032613464653462
30383039623036393239383966326333663531356537343539333633623036396132646338393332
33653564633165356663636663386232346239303835613739356430386636386137653861306661
64313238306139383066633963333563633235636632613862313862343738633338303638383362
32653630626333613036306366353065663231623263613737626633366236616432383530346633
63306265333461313230346633636662353932336562376636646135633063653031383061626530
35653963363466353263396663313333646661386262393866643762356635353363636235353031
33393732623264353737356131633039653564626334623362383361646436316336343962353830
32303635666134613033666664326235663566646162336161333663333665613266326564616339
34303565306466346662336464666537643037633837353263346363313939623166653539323032
64623731376137393664653039623761366230356566316135613031623363323437343664656261
35626439313232353166666636333263633831653863653939643862323535626439323539626639
35363764303565346336323965383334336562306231656366643066653962356636383436336163
37343435353430363663616232326266333662303462616634633637613432346264366537323062
66323865643738373639356434386232656630383562656336363538356633363134343163343162
62663438393332376166663434366662616565616633636334643536656436643131303432303231
31313639613062323763303336323336646632303834366233633939616230353431356538363636
65623562326637363233333666623532326633643864653261363836626565313537366632653363
64333231663538663739636630356336336565323666373436613337633864313761653664643566
38666439626633353462623236626633613263303265623733636433633666643339356632366133
32616532646466343563636336663230333337366466656232323865333431616434306466646433
62626437316130623839663166323264333866613866323061393662663935363339363337636663
66623634373864613464623230373434363461336461373233616533373461343030313166386230
61623637636630666264346637333961623730356366313336313663643539393138343830346138
34643337343031373566656537626533633131646631383962373437666337303764636163623931
65373737316234666465363839313566323338313939653032643362613962316139

2
provisioning/hosts Normal file
View File

@ -0,0 +1,2 @@
[production]
regluit-prod ansible_host=m.unglue.it ansible_user=ubuntu

View File

@ -0,0 +1,21 @@
project_path: "/opt/regluit"
django_settings_module: "regluit.settings.me"
virtualenv_name: "venv"
# MySQL
mysql_db_name: "regluit"
mysql_db_user: "regluit"
mysql_db_pass: "password123"
mysql_db_host: "localhost"
mysql_db_port: 3306
# Task Broker
broker_transport: "redis"
broker_host: "localhost"
broker_port: 6379
broker_vhost: "0"
# Common.py defaults
boxstream_api_key: "012345678901234567890123456789"
boxstream_api_user: "user"
dropbox_key: "012345678901234"

View File

@ -0,0 +1,154 @@
#!/bin/bash
# =========================================================
# celerybeat - Starts the Celery periodic task scheduler.
# =========================================================
#
# :Usage: /etc/init.d/celerybeat {start|stop|force-reload|restart|try-restart|status}
# :Configuration file: /etc/default/celerybeat or /etc/default/celeryd
#
# See http://docs.celeryq.org/en/latest/cookbook/daemonizing.html#init-script-celerybeat
# This file is copied from https://github.com/ask/celery/blob/2.4/contrib/generic-init.d/celerybeat
### BEGIN INIT INFO
# Provides: celerybeat
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: celery periodic task scheduler
### END INIT INFO
# Cannot use set -e/bash -e since the kill -0 command will abort
# abnormally in the absence of a valid process ID.
#set -e
DEFAULT_PID_FILE="/var/run/celerybeat.pid"
DEFAULT_LOG_FILE="/var/log/celerybeat.log"
DEFAULT_LOG_LEVEL="INFO"
DEFAULT_CELERYBEAT="celerybeat"
# /etc/init.d/ssh: start and stop the celery task worker daemon.
if test -f /etc/default/celeryd; then
. /etc/default/celeryd
fi
if test -f /etc/default/celerybeat; then
. /etc/default/celerybeat
fi
CELERYBEAT=${CELERYBEAT:-$DEFAULT_CELERYBEAT}
CELERYBEAT_PID_FILE=${CELERYBEAT_PID_FILE:-${CELERYBEAT_PIDFILE:-$DEFAULT_PID_FILE}}
CELERYBEAT_LOG_FILE=${CELERYBEAT_LOG_FILE:-${CELERYBEAT_LOGFILE:-$DEFAULT_LOG_FILE}}
CELERYBEAT_LOG_LEVEL=${CELERYBEAT_LOG_LEVEL:-${CELERYBEAT_LOGLEVEL:-$DEFAULT_LOG_LEVEL}}
export CELERY_LOADER
CELERYBEAT_OPTS="$CELERYBEAT_OPTS -f $CELERYBEAT_LOG_FILE -l $CELERYBEAT_LOG_LEVEL"
if [ -n "$2" ]; then
CELERYBEAT_OPTS="$CELERYBEAT_OPTS $2"
fi
CELERYBEAT_LOG_DIR=`dirname $CELERYBEAT_LOG_FILE`
CELERYBEAT_PID_DIR=`dirname $CELERYBEAT_PID_FILE`
if [ ! -d "$CELERYBEAT_LOG_DIR" ]; then
mkdir -p $CELERYBEAT_LOG_DIR
fi
if [ ! -d "$CELERYBEAT_PID_DIR" ]; then
mkdir -p $CELERYBEAT_PID_DIR
fi
# Extra start-stop-daemon options, like user/group.
if [ -n "$CELERYBEAT_USER" ]; then
DAEMON_OPTS="$DAEMON_OPTS --uid $CELERYBEAT_USER"
chown "$CELERYBEAT_USER" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR
fi
if [ -n "$CELERYBEAT_GROUP" ]; then
DAEMON_OPTS="$DAEMON_OPTS --gid $CELERYBEAT_GROUP"
chgrp "$CELERYBEAT_GROUP" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR
fi
CELERYBEAT_CHDIR=${CELERYBEAT_CHDIR:-$CELERYD_CHDIR}
if [ -n "$CELERYBEAT_CHDIR" ]; then
DAEMON_OPTS="$DAEMON_OPTS --workdir $CELERYBEAT_CHDIR"
fi
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
check_dev_null() {
if [ ! -c /dev/null ]; then
echo "/dev/null is not a character device!"
exit 1
fi
}
wait_pid () {
pid=$1
forever=1
i=0
while [ $forever -gt 0 ]; do
kill -0 $pid 1>/dev/null 2>&1
if [ $? -eq 1 ]; then
echo "OK"
forever=0
else
kill -TERM "$pid"
i=$((i + 1))
if [ $i -gt 60 ]; then
echo "ERROR"
echo "Timed out while stopping (30s)"
forever=0
else
sleep 0.5
fi
fi
done
}
stop_beat () {
echo -n "Stopping celerybeat... "
if [ -f "$CELERYBEAT_PID_FILE" ]; then
wait_pid $(cat "$CELERYBEAT_PID_FILE")
else
echo "NOT RUNNING"
fi
}
start_beat () {
echo "Starting celerybeat..."
if [ -n "$VIRTUALENV" ]; then
source $VIRTUALENV/bin/activate
fi
$CELERYBEAT $CELERYBEAT_OPTS $DAEMON_OPTS --detach \
--pidfile="$CELERYBEAT_PID_FILE"
}
case "$1" in
start)
check_dev_null
start_beat
;;
stop)
stop_beat
;;
reload|force-reload)
echo "Use start+stop"
;;
restart)
echo "Restarting celery periodic task scheduler"
stop_beat
check_dev_null
start_beat
;;
*)
echo "Usage: /etc/init.d/celerybeat {start|stop|restart}"
exit 1
esac
exit 0

View File

@ -0,0 +1,217 @@
#!/bin/bash
# ============================================
# celeryd - Starts the Celery worker daemon.
# ============================================
#
# :Usage: /etc/init.d/celeryd {start|stop|force-reload|restart|try-restart|status}
#
# :Configuration file: /etc/default/celeryd
#
# To configure celeryd you probably need to tell it where to chdir.
#
# EXAMPLE CONFIGURATION
# =====================
#
# this is an example configuration for a Python project:
#
# /etc/default/celeryd:
#
# # List of nodes to start
# CELERYD_NODES="worker1 worker2 worker3"k
# # ... can also be a number of workers
# CELERYD_NODES=3
#
# # Where to chdir at start.
# CELERYD_CHDIR="/opt/Myproject/"
#
# # Extra arguments to celeryd
# CELERYD_OPTS="--time-limit=300"
#
# # Name of the celery config module.#
# CELERY_CONFIG_MODULE="celeryconfig"
#
# EXAMPLE DJANGO CONFIGURATION
# ============================
#
# # Where the Django project is.
# CELERYD_CHDIR="/opt/Project/"
#
# # Name of the projects settings module.
# export DJANGO_SETTINGS_MODULE="settings"
#
# # Path to celeryd
# CELERYD="/opt/Project/manage.py celeryd"
#
# AVAILABLE OPTIONS
# =================
#
# * CELERYD_NODES
#
# A space separated list of nodes, or a number describing the number of
# nodes, to start
#
# * CELERYD_OPTS
# Additional arguments to celeryd-multi, see `celeryd-multi --help`
# and `celeryd --help` for help.
#
# * CELERYD_CHDIR
# Path to chdir at start. Default is to stay in the current directory.
#
# * CELERYD_PIDFILE
# Full path to the pidfile. Default is /var/run/celeryd.pid.
#
# * CELERYD_LOGFILE
# Full path to the celeryd logfile. Default is /var/log/celeryd.log
#
# * CELERYD_LOG_LEVEL
# Log level to use for celeryd. Default is INFO.
#
# * CELERYD
# Path to the celeryd program. Default is `celeryd`.
# You can point this to an virtualenv, or even use manage.py for django.
#
# * CELERYD_USER
# User to run celeryd as. Default is current user.
#
# * CELERYD_GROUP
# Group to run celeryd as. Default is current user.
# VARIABLE EXPANSION
# ==================
#
# The following abbreviations will be expanded
#
# * %n -> node name
# * %h -> host name
### BEGIN INIT INFO
# Provides: celeryd
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: celery task worker daemon
### END INIT INFO
#set -e
DEFAULT_PID_FILE="/var/run/celeryd@%n.pid"
DEFAULT_LOG_FILE="/var/log/celeryd@%n.log"
DEFAULT_LOG_LEVEL="INFO"
DEFAULT_NODES="celery"
DEFAULT_CELERYD="-m celery.bin.celeryd_detach"
# /etc/init.d/celeryd: start and stop the celery task worker daemon.
CELERY_DEFAULTS=${CELERY_DEFAULTS:-"/etc/default/celeryd"}
test -f "$CELERY_DEFAULTS" && . "$CELERY_DEFAULTS"
if [ -f "/etc/default/celeryd" ]; then
. /etc/default/celeryd
fi
if [ -f $VIRTUALENV_ACTIVATE ]; then
echo "activating virtualenv $VIRTUALENV_ACTIVATE"
source "$VIRTUALENV_ACTIVATE"
fi
CELERYD_PID_FILE=${CELERYD_PID_FILE:-${CELERYD_PIDFILE:-$DEFAULT_PID_FILE}}
CELERYD_LOG_FILE=${CELERYD_LOG_FILE:-${CELERYD_LOGFILE:-$DEFAULT_LOG_FILE}}
CELERYD_LOG_LEVEL=${CELERYD_LOG_LEVEL:-${CELERYD_LOGLEVEL:-$DEFAULT_LOG_LEVEL}}
CELERYD_MULTI=${CELERYD_MULTI:-"celeryd-multi"}
CELERYD=${CELERYD:-$DEFAULT_CELERYD}
CELERYD_NODES=${CELERYD_NODES:-$DEFAULT_NODES}
export CELERY_LOADER
if [ -n "$2" ]; then
CELERYD_OPTS="$CELERYD_OPTS $2"
fi
# Extra start-stop-daemon options, like user/group.
if [ -n "$CELERYD_USER" ]; then
DAEMON_OPTS="$DAEMON_OPTS --uid=$CELERYD_USER"
fi
if [ -n "$CELERYD_GROUP" ]; then
DAEMON_OPTS="$DAEMON_OPTS --gid=$CELERYD_GROUP"
fi
if [ -n "$CELERYD_CHDIR" ]; then
DAEMON_OPTS="$DAEMON_OPTS --workdir=\"$CELERYD_CHDIR\""
fi
check_dev_null() {
if [ ! -c /dev/null ]; then
echo "/dev/null is not a character device!"
exit 1
fi
}
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
stop_workers () {
$CELERYD_MULTI stop $CELERYD_NODES --pidfile="$CELERYD_PID_FILE"
}
start_workers () {
$CELERYD_MULTI start $CELERYD_NODES $DAEMON_OPTS \
--pidfile="$CELERYD_PID_FILE" \
--logfile="$CELERYD_LOG_FILE" \
--loglevel="$CELERYD_LOG_LEVEL" \
--cmd="$CELERYD" \
$CELERYD_OPTS
}
restart_workers () {
$CELERYD_MULTI restart $CELERYD_NODES $DAEMON_OPTS \
--pidfile="$CELERYD_PID_FILE" \
--logfile="$CELERYD_LOG_FILE" \
--loglevel="$CELERYD_LOG_LEVEL" \
--cmd="$CELERYD" \
$CELERYD_OPTS
}
case "$1" in
start)
check_dev_null
start_workers
;;
stop)
check_dev_null
stop_workers
;;
reload|force-reload)
echo "Use restart"
;;
status)
celeryctl status
;;
restart)
check_dev_null
restart_workers
;;
try-restart)
check_dev_null
restart_workers
;;
*)
echo "Usage: /etc/init.d/celeryd {start|stop|restart|try-restart|kill}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,37 @@
---
# Tasks for Celeryd and Celerybeat processes
- name: Create /var/log/celery
become: true
file:
path: "/var/log/celery"
state: directory
#owner: celery
#group: celery
mode: 0775
- name: Create /var/run/celery
become: true
file:
path: "/var/run/celery"
state: directory
#owner: celery
#group: celery
mode: 0775
- name: Copy celery init.d scripts
become: true
copy:
src: "{{ item }}"
dest: "/etc/init.d/{{ item }}"
with_items:
- 'celeryd'
- 'celerybeat'
- name: Copy celery config files
become: true
template:
src: "celery/{{ item }}.j2"
dest: "/etc/default/{{ item }}"
with_items:
- 'celeryd'
- 'celerybeat'

View File

@ -0,0 +1,85 @@
---
# Need to install python2.7 and pip first so Ansible will function
# This is due to Ubuntu 16 shipping with Python3 by default
- name: Install python2.7 and pip
become: true
raw: bash -c "apt -qqy update && apt install -qqy python2.7-dev python-pip"
register: output
changed_when: output.stdout != ""
- name: Gathering Facts
setup:
- name: Install base regluit dependencies
become: true
apt:
name: "{{ item }}"
update_cache: true
state: present
with_items:
- 'git'
- 'python-setuptools'
- 'python-lxml'
- 'build-essential'
- 'libssl-dev'
- 'libffi-dev'
- 'libxml2-dev'
- 'libxslt-dev'
- 'mysql-server'
- 'mysql-client'
- 'libmysqlclient-dev'
- 'python-mysqldb'
- name: Install virtualenv
pip:
name: "virtualenv"
state: present
- name: Install python packages to virtualenv
pip:
requirements: "{{ project_path }}/requirements_versioned.pip"
state: present
virtualenv: "{{ project_path }}/venv"
- name: Add project to PYTHONPATH of virtualenv
template:
src: "{{ item }}.j2"
dest: "{{ project_path }}/venv/lib/python2.7/site-packages/{{ item }}"
with_items:
- 'regluit.pth'
- 'opt.pth'
- name: Create keys directory
file:
path: "{{ project_path}}/settings/keys"
state: directory
- name: Copy keys files
copy:
src: "{{ project_path }}/settings/dummy/__init__.py"
dest: "{{ project_path }}/settings/keys/__init__.py"
remote_src: yes
- name: Copy django settings template
template:
src: me.py.j2
dest: "{{ project_path }}/settings/me.py"
- name: Copy key templates to keys directory
template:
src: "{{ item }}.j2"
dest: "{{ project_path }}/settings/keys/{{ item }}"
with_items:
- 'common.py'
- 'host.py'
- name: MySQL setup
become: true
import_tasks: mysql.yml
- name: Redis setup
become: true
import_tasks: redis.yml
# - name: Celery setup
# import_tasks: celery.yml

View File

@ -0,0 +1,12 @@
---
- name: Create MySQL database
mysql_db:
name: "{{ mysql_db_name }}"
state: present
- name: Create MySQL user
mysql_user:
name: "{{ mysql_db_user }}"
password: "{{ mysql_db_pass }}"
priv: '*.*:ALL'
state: present

View File

@ -0,0 +1,13 @@
---
- name: Install Redis server
become: yes
apt:
name: "redis-server"
state: present
- name: Ensure Redis is started
become: yes
service:
name: "redis-server"
state: started
enabled: yes

View File

@ -0,0 +1,35 @@
# http://docs.celeryproject.org/en/latest/cookbook/daemonizing.html#generic-initd-celerybeat-example
# to be placed at /etc/defaults/celerybeat
# Where to chdir at start.
CELERYBEAT_CHDIR="{{ project_path }}t/"
# Extra arguments to celerybeat
#CELERYBEAT_OPTS="--schedule=/var/run/celerybeat-schedule"
# Name of the celery config module.#
CELERY_CONFIG_MODULE="celeryconfig"
# Name of the projects settings module.
export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}"
# Path to celerybeat
CELERYBEAT="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celerybeat"
# virtualenv to use
VIRTUALENV="{{ project_path }}/{{ virtualenv_name }}"
#Full path to the PID file. Default is /var/run/celeryd.pid
CELERYBEAT_PIDFILE="/var/log/celerybeat/celerybeat.pid"
#Full path to the celeryd log file. Default is /var/log/celeryd.log
CELERYBEAT_LOGFILE="/var/log/celerybeat/celerybeat.log"
#Log level to use for celeryd. Default is INFO.
CELERYBEAT_LOG_LEVEL="INFO"
#User to run celeryd as. Default is current user.
#CELERYBEAT_USER
#Group to run celeryd as. Default is current user.
#CELERYBEAT_GROUP

View File

@ -0,0 +1,9 @@
CELERYD_NODES="w1"
CELERYD_CHDIR="{{ project_path }}/"
CELERYD_LOG_FILE="/var/log/celery/%n.log"
CELERYD_PID_FILE="/var/log/celery/%n.pid"
CELERYD="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd"
CELERYD_MULTI="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd_multi"
VIRTUALENV_ACTIVATE="{{ project_path }}/{{ virtualenv_name }}/bin/activate"
export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}"

View File

@ -0,0 +1,13 @@
import os
# all the COMMON_KEYS
# copy this file to settings/keys/ and replace the dummy values with real ones
BOOXTREAM_API_KEY = os.environ.get('BOOXTREAM_API_KEY', '{{ boxstream_api_key }}')
BOOXTREAM_API_USER = os.environ.get('BOOXTREAM_API_USER', '{{ boxstream_api_user }}')
DROPBOX_KEY = os.environ.get('DROPBOX_KEY', '{{ dropbox_key }}')
GITHUB_PUBLIC_TOKEN = os.environ.get('GITHUB_PUBLIC_TOKEN', None) # 40 chars; null has lower limit
MAILCHIMP_API_KEY = os.environ.get('MAILCHIMP_API_KEY', '-us2') # [32chars]-xx#
MAILCHIMP_NEWS_ID = os.environ.get('MAILCHIMP_NEWS_ID', '0123456789')
MOBIGEN_PASSWORD = os.environ.get('MOBIGEN_PASSWORD', '012345678901234')
MOBIGEN_URL = os.environ.get('MOBIGEN_URL', '') # https://host/mobigen
MOBIGEN_USER_ID = os.environ.get('MOBIGEN_USER_ID', 'user')

View File

@ -0,0 +1,47 @@
# host.py
# copy this file to settings/keys/ and replace the dummy values with real ones
# or generate it from the ansible vault
import os
# you can use this to generate a key: http://www.miniwebtool.com/django-secret-key-generator/
SECRET_KEY = os.environ.get("SECRET_KEY", '01234567890123456789012345678901234567890123456789')
# you'll need to register a GoogleBooks API key
# https://code.google.com/apis/console
GOOGLE_BOOKS_API_KEY = os.environ.get("GOOGLE_BOOKS_API_KEY", "012345678901234567890123456789012345678")
#
GOODREADS_API_KEY = os.environ.get("GOODREADS_API_KEY", "01234567890123456789")
GOODREADS_API_SECRET = os.environ.get("GOODREADS_API_SECRET", None) #43 chars
# Amazon SES
# create with https://console.aws.amazon.com/ses/home?region=us-east-1#smtp-settings:
EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", '01234567890123456789')
EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", '01234567890123456789012345678901234567890123')
# twitter auth
# you'll need to create a new Twitter application to fill in these blanks
# https://dev.twitter.com/apps/new
SOCIAL_AUTH_TWITTER_KEY = os.environ.get("SOCIAL_AUTH_TWITTER_KEY", '0123456789012345678901234')
SOCIAL_AUTH_TWITTER_SECRET = os.environ.get("SOCIAL_AUTH_TWITTER_SECRET", '01234567890123456789012345678901234567890123456789')
# support@icontact.nl
BOOXTREAM_API_KEY = os.environ.get("BOOXTREAM_API_KEY", None) # 30 chars
BOOXTREAM_API_USER = os.environ.get("BOOXTREAM_API_USER", 'user')
# you'll need to create a new Facebook application to fill in these blanks
# https://developers.facebook.com/apps/
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get("SOCIAL_AUTH_FACEBOOK_KEY", '012345678901234')
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get("SOCIAL_AUTH_FACEBOOK_SECRET", '01234567890123456789012345678901')
# https://console.developers.google.com/apis/credentials/oauthclient/
# unglue.it (prod) SOCIAL_AUTH_GOOGLE_OAUTH2_KEY #2
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("_KEY", '012345678901-01234567890123456789012345678901.apps.googleusercontent.com')
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("_SECRET", '012345678901234567890123')
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", '01234567890123456789')
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", '') # 40 chars
DATABASE_USER = os.environ.get("DATABASE_USER", 'root')
DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD", '')
DATABASE_HOST = os.environ.get("DATABASE_HOST", '')

View File

@ -0,0 +1,90 @@
# coding=utf-8
from .common import *
try:
from .keys.host import *
except ImportError:
from .dummy.host import *
DEBUG = True
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
# if you're doing development work, you'll want this to be zero
IS_PREVIEW = False
# SITE_ID for your particular site -- must be configured in /core/fixtures/initial_data.json
SITE_ID = 3
ADMINS = (
('Raymond Yee', 'rdhyee+ungluebugs@gluejar.com'),
('Eric Hellman', 'eric@gluejar.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '{{ mysql_db_name }}',
'USER': '{{ mysql_db_user }}',
'PASSWORD': '{{ mysql_db_pass }}',
'HOST': '{{ mysql_db_host }}',
'PORT': '{{ mysql_db_port }} ',
'TEST_CHARSET': 'utf8',
}
}
STATIC_ROOT = '/var/www/static'
CKEDITOR_UPLOAD_PATH = '/var/www/static/media/'
TIME_ZONE = 'America/New_York'
# settings for outbout email
# if you have a gmail account you can use your email address and password
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_HOST_USER is in keys/host
# EMAIL_HOST_PASSWORD is in keys/host
EMAIL_PORT = 587
DEFAULT_FROM_EMAIL = 'info@ebookfoundation.org'
# for use with test google account only
GOOGLE_DISPLAY_NAME = 'Unglue.It'
REDIRECT_IS_HTTPS = False
#BASE_URL = 'http://0.0.0.0'
BASE_URL_SECURE = 'https://0.0.0.0'
# use redis as queuing service
BROKER_TRANSPORT = "{{ broker_transport }}"
BROKER_HOST = "{{ broker_host }}"
BROKER_PORT = {{ broker_port }}
BROKER_VHOST = "{{ broker_vhost }}"
# send celery log to Python logging
CELERYD_HIJACK_ROOT_LOGGER = False
# a debug_toolbar setting
INTERNAL_IPS = ('127.0.0.1',)
CELERYD_LOG_LEVEL = "INFO"
# decide which of the period tasks to add to the schedule
#CELERYBEAT_SCHEDULE['send_test_email'] = SEND_TEST_EMAIL_JOB
#CELERYBEAT_SCHEDULE['refresh_acqs'] = REFRESH_ACQS_JOB
# if you're doing development work, you'll want this to be zero
IS_PREVIEW = False
# username, password to pass to LIVE_SERVER_TEST_URL
UNGLUEIT_TEST_USER = None
UNGLUEIT_TEST_PASSWORD = None
# local settings for maintenance mode
MAINTENANCE_MODE = False
# assume that CSS will get generated on dev
SASS_OUTPUT_STYLE = 'compressed'

View File

@ -0,0 +1 @@
/opt/

View File

@ -0,0 +1 @@
{{ project_path }}/

View File

@ -0,0 +1,5 @@
django_settings_module: "regluit.settings.me"
project_path: "/opt/regluit"
virtualenv_name: "venv"
django_server_ip: "0.0.0.0"
django_server_port: 8000

View File

@ -0,0 +1,69 @@
---
- name: Install dev dependencies
become: true
apt:
name: "{{ item }}"
update_cache: true
state: present
with_items:
- 'git'
- 'python-setuptools'
- 'python-lxml'
- 'build-essential'
- 'libssl-dev'
- 'libffi-dev'
- 'libxml2-dev'
- 'libxslt-dev'
- 'mysql-server'
- 'mysql-client'
- 'libmysqlclient-dev'
- 'python-mysqldb'
- name: Migrate databse
django_manage:
app_path: "{{ project_path }}"
command: "migrate --noinput"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
- name: Import fixtures
django_manage:
app_path: "{{ project_path }}"
command: "loaddata"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
fixtures: "core/fixtures/initial_data.json core/fixtures/bookloader.json"
- name: Start Celery Worker
django_manage:
app_path: "{{ project_path }}"
command: "celery worker --detach --loglevel=INFO"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
- name: Start Celery Beat
django_manage:
app_path: "{{ project_path }}"
command: "celery beat --detach --loglevel=INFO"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
- name: Copy activation script
template:
src: "activate_venv.sh.j2"
dest: "/home/{{ ansible_user }}/activate_venv.sh"
owner: "{{ ansible_user }}"
mode: "u=rx,g=rx,o=rwx"
- name: Source activation script in bash profile
blockinfile:
path: "/home/{{ ansible_user }}/.profile"
block: |
if [ -f ~/activate_venv.sh ]; then
source ~/activate_venv.sh
fi
marker: "# {mark} SOURCE REGLUIT ACTIVATION SCRIPT ON LOGIN"
- debug:
msg: "Successfully provisioned regluit development environment."

View File

@ -0,0 +1,7 @@
#!/bin/bash
cd {{ project_path }}
source {{ virtualenv_name }}/bin/activate
echo Local setup of Regluit complete!
echo To start the django development server, run:
echo ./manage.py runserver {{ django_server_ip }}:{{ django_server_port }}
echo Then leave this session running and access the site on your host machine at http://127.0.0.1:{{ django_server_port }}

View File

@ -0,0 +1,154 @@
#!/bin/bash
# =========================================================
# celerybeat - Starts the Celery periodic task scheduler.
# =========================================================
#
# :Usage: /etc/init.d/celerybeat {start|stop|force-reload|restart|try-restart|status}
# :Configuration file: /etc/default/celerybeat or /etc/default/celeryd
#
# See http://docs.celeryq.org/en/latest/cookbook/daemonizing.html#init-script-celerybeat
# This file is copied from https://github.com/ask/celery/blob/2.4/contrib/generic-init.d/celerybeat
### BEGIN INIT INFO
# Provides: celerybeat
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: celery periodic task scheduler
### END INIT INFO
# Cannot use set -e/bash -e since the kill -0 command will abort
# abnormally in the absence of a valid process ID.
#set -e
DEFAULT_PID_FILE="/var/run/celerybeat.pid"
DEFAULT_LOG_FILE="/var/log/celerybeat.log"
DEFAULT_LOG_LEVEL="INFO"
DEFAULT_CELERYBEAT="celerybeat"
# /etc/init.d/ssh: start and stop the celery task worker daemon.
if test -f /etc/default/celeryd; then
. /etc/default/celeryd
fi
if test -f /etc/default/celerybeat; then
. /etc/default/celerybeat
fi
CELERYBEAT=${CELERYBEAT:-$DEFAULT_CELERYBEAT}
CELERYBEAT_PID_FILE=${CELERYBEAT_PID_FILE:-${CELERYBEAT_PIDFILE:-$DEFAULT_PID_FILE}}
CELERYBEAT_LOG_FILE=${CELERYBEAT_LOG_FILE:-${CELERYBEAT_LOGFILE:-$DEFAULT_LOG_FILE}}
CELERYBEAT_LOG_LEVEL=${CELERYBEAT_LOG_LEVEL:-${CELERYBEAT_LOGLEVEL:-$DEFAULT_LOG_LEVEL}}
export CELERY_LOADER
CELERYBEAT_OPTS="$CELERYBEAT_OPTS -f $CELERYBEAT_LOG_FILE -l $CELERYBEAT_LOG_LEVEL"
if [ -n "$2" ]; then
CELERYBEAT_OPTS="$CELERYBEAT_OPTS $2"
fi
CELERYBEAT_LOG_DIR=`dirname $CELERYBEAT_LOG_FILE`
CELERYBEAT_PID_DIR=`dirname $CELERYBEAT_PID_FILE`
if [ ! -d "$CELERYBEAT_LOG_DIR" ]; then
mkdir -p $CELERYBEAT_LOG_DIR
fi
if [ ! -d "$CELERYBEAT_PID_DIR" ]; then
mkdir -p $CELERYBEAT_PID_DIR
fi
# Extra start-stop-daemon options, like user/group.
if [ -n "$CELERYBEAT_USER" ]; then
DAEMON_OPTS="$DAEMON_OPTS --uid $CELERYBEAT_USER"
chown "$CELERYBEAT_USER" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR
fi
if [ -n "$CELERYBEAT_GROUP" ]; then
DAEMON_OPTS="$DAEMON_OPTS --gid $CELERYBEAT_GROUP"
chgrp "$CELERYBEAT_GROUP" $CELERYBEAT_LOG_DIR $CELERYBEAT_PID_DIR
fi
CELERYBEAT_CHDIR=${CELERYBEAT_CHDIR:-$CELERYD_CHDIR}
if [ -n "$CELERYBEAT_CHDIR" ]; then
DAEMON_OPTS="$DAEMON_OPTS --workdir $CELERYBEAT_CHDIR"
fi
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
check_dev_null() {
if [ ! -c /dev/null ]; then
echo "/dev/null is not a character device!"
exit 1
fi
}
wait_pid () {
pid=$1
forever=1
i=0
while [ $forever -gt 0 ]; do
kill -0 $pid 1>/dev/null 2>&1
if [ $? -eq 1 ]; then
echo "OK"
forever=0
else
kill -TERM "$pid"
i=$((i + 1))
if [ $i -gt 60 ]; then
echo "ERROR"
echo "Timed out while stopping (30s)"
forever=0
else
sleep 0.5
fi
fi
done
}
stop_beat () {
echo -n "Stopping celerybeat... "
if [ -f "$CELERYBEAT_PID_FILE" ]; then
wait_pid $(cat "$CELERYBEAT_PID_FILE")
else
echo "NOT RUNNING"
fi
}
start_beat () {
echo "Starting celerybeat..."
if [ -n "$VIRTUALENV" ]; then
source $VIRTUALENV/bin/activate
fi
$CELERYBEAT $CELERYBEAT_OPTS $DAEMON_OPTS --detach \
--pidfile="$CELERYBEAT_PID_FILE"
}
case "$1" in
start)
check_dev_null
start_beat
;;
stop)
stop_beat
;;
reload|force-reload)
echo "Use start+stop"
;;
restart)
echo "Restarting celery periodic task scheduler"
stop_beat
check_dev_null
start_beat
;;
*)
echo "Usage: /etc/init.d/celerybeat {start|stop|restart}"
exit 1
esac
exit 0

View File

@ -0,0 +1,217 @@
#!/bin/bash
# ============================================
# celeryd - Starts the Celery worker daemon.
# ============================================
#
# :Usage: /etc/init.d/celeryd {start|stop|force-reload|restart|try-restart|status}
#
# :Configuration file: /etc/default/celeryd
#
# To configure celeryd you probably need to tell it where to chdir.
#
# EXAMPLE CONFIGURATION
# =====================
#
# this is an example configuration for a Python project:
#
# /etc/default/celeryd:
#
# # List of nodes to start
# CELERYD_NODES="worker1 worker2 worker3"k
# # ... can also be a number of workers
# CELERYD_NODES=3
#
# # Where to chdir at start.
# CELERYD_CHDIR="/opt/Myproject/"
#
# # Extra arguments to celeryd
# CELERYD_OPTS="--time-limit=300"
#
# # Name of the celery config module.#
# CELERY_CONFIG_MODULE="celeryconfig"
#
# EXAMPLE DJANGO CONFIGURATION
# ============================
#
# # Where the Django project is.
# CELERYD_CHDIR="/opt/Project/"
#
# # Name of the projects settings module.
# export DJANGO_SETTINGS_MODULE="settings"
#
# # Path to celeryd
# CELERYD="/opt/Project/manage.py celeryd"
#
# AVAILABLE OPTIONS
# =================
#
# * CELERYD_NODES
#
# A space separated list of nodes, or a number describing the number of
# nodes, to start
#
# * CELERYD_OPTS
# Additional arguments to celeryd-multi, see `celeryd-multi --help`
# and `celeryd --help` for help.
#
# * CELERYD_CHDIR
# Path to chdir at start. Default is to stay in the current directory.
#
# * CELERYD_PIDFILE
# Full path to the pidfile. Default is /var/run/celeryd.pid.
#
# * CELERYD_LOGFILE
# Full path to the celeryd logfile. Default is /var/log/celeryd.log
#
# * CELERYD_LOG_LEVEL
# Log level to use for celeryd. Default is INFO.
#
# * CELERYD
# Path to the celeryd program. Default is `celeryd`.
# You can point this to an virtualenv, or even use manage.py for django.
#
# * CELERYD_USER
# User to run celeryd as. Default is current user.
#
# * CELERYD_GROUP
# Group to run celeryd as. Default is current user.
# VARIABLE EXPANSION
# ==================
#
# The following abbreviations will be expanded
#
# * %n -> node name
# * %h -> host name
### BEGIN INIT INFO
# Provides: celeryd
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: celery task worker daemon
### END INIT INFO
#set -e
DEFAULT_PID_FILE="/var/run/celeryd@%n.pid"
DEFAULT_LOG_FILE="/var/log/celeryd@%n.log"
DEFAULT_LOG_LEVEL="INFO"
DEFAULT_NODES="celery"
DEFAULT_CELERYD="-m celery.bin.celeryd_detach"
# /etc/init.d/celeryd: start and stop the celery task worker daemon.
CELERY_DEFAULTS=${CELERY_DEFAULTS:-"/etc/default/celeryd"}
test -f "$CELERY_DEFAULTS" && . "$CELERY_DEFAULTS"
if [ -f "/etc/default/celeryd" ]; then
. /etc/default/celeryd
fi
if [ -f $VIRTUALENV_ACTIVATE ]; then
echo "activating virtualenv $VIRTUALENV_ACTIVATE"
source "$VIRTUALENV_ACTIVATE"
fi
CELERYD_PID_FILE=${CELERYD_PID_FILE:-${CELERYD_PIDFILE:-$DEFAULT_PID_FILE}}
CELERYD_LOG_FILE=${CELERYD_LOG_FILE:-${CELERYD_LOGFILE:-$DEFAULT_LOG_FILE}}
CELERYD_LOG_LEVEL=${CELERYD_LOG_LEVEL:-${CELERYD_LOGLEVEL:-$DEFAULT_LOG_LEVEL}}
CELERYD_MULTI=${CELERYD_MULTI:-"celeryd-multi"}
CELERYD=${CELERYD:-$DEFAULT_CELERYD}
CELERYD_NODES=${CELERYD_NODES:-$DEFAULT_NODES}
export CELERY_LOADER
if [ -n "$2" ]; then
CELERYD_OPTS="$CELERYD_OPTS $2"
fi
# Extra start-stop-daemon options, like user/group.
if [ -n "$CELERYD_USER" ]; then
DAEMON_OPTS="$DAEMON_OPTS --uid=$CELERYD_USER"
fi
if [ -n "$CELERYD_GROUP" ]; then
DAEMON_OPTS="$DAEMON_OPTS --gid=$CELERYD_GROUP"
fi
if [ -n "$CELERYD_CHDIR" ]; then
DAEMON_OPTS="$DAEMON_OPTS --workdir=\"$CELERYD_CHDIR\""
fi
check_dev_null() {
if [ ! -c /dev/null ]; then
echo "/dev/null is not a character device!"
exit 1
fi
}
export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
stop_workers () {
$CELERYD_MULTI stop $CELERYD_NODES --pidfile="$CELERYD_PID_FILE"
}
start_workers () {
$CELERYD_MULTI start $CELERYD_NODES $DAEMON_OPTS \
--pidfile="$CELERYD_PID_FILE" \
--logfile="$CELERYD_LOG_FILE" \
--loglevel="$CELERYD_LOG_LEVEL" \
--cmd="$CELERYD" \
$CELERYD_OPTS
}
restart_workers () {
$CELERYD_MULTI restart $CELERYD_NODES $DAEMON_OPTS \
--pidfile="$CELERYD_PID_FILE" \
--logfile="$CELERYD_LOG_FILE" \
--loglevel="$CELERYD_LOG_LEVEL" \
--cmd="$CELERYD" \
$CELERYD_OPTS
}
case "$1" in
start)
check_dev_null
start_workers
;;
stop)
check_dev_null
stop_workers
;;
reload|force-reload)
echo "Use restart"
;;
status)
celeryctl status
;;
restart)
check_dev_null
restart_workers
;;
try-restart)
check_dev_null
restart_workers
;;
*)
echo "Usage: /etc/init.d/celeryd {start|stop|restart|try-restart|kill}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,210 @@
$ANSIBLE_VAULT;1.1;AES256
30636262636630653738383536613136363733643931316362326266656433376333386239373962
6635343138326335313430623566656130663136393531310a343562653666623235336539316561
31386163663632383436343735376266356134386335363637383536613531323231626535313236
6163326630306530360a663636393463303062316331623630353235383137333831333239393134
64353830366463376130633831633835313034643930636166396436373063623039316465613964
61333538656264353735613034356533353331313735393965363164616331306538383231303932
31373838363862343931643034643863313738636238376634363430613365356136323237613530
34323339323337383539363462303863663163373465373262636161346662333738663532316363
65313464333363643461353539306662353364643663373032346531633362373230653061646436
34393462326137336163316361363937323738663632386662643338626433626433633235323838
65653036643961626131383264393138316263366534656663386264376638393639636164323661
61646166376637396131356339313162343762636234643236316363643063326638366536656534
31616164313164373336666634356639653831623966333739356462656137363161663635353136
30653665353334646165663333643863643539373331613263386561353030363862666264353933
64643439336236386631393934623839626163373463653134656539376262316233626130363663
65636534303431616631633534643030346534633635393563366266356138383938636264383632
33616365333863393733646565643236613064616462633661303630613963666236663265636361
61376336346262346632313833633735356364636239366439393265613866316439643732326330
38396332363666656636646164646262303162656331636661393738626263383563646261323036
63363634616362323965616639373961333966303366363937333233356631393938383339613262
39393461316563383131666539333938313437336462376233353464303739356463323265366665
64316161333431353264336236373466613230363237316633386661303538666536366462323666
32373164626330313665653133356563383436663765666437636138343163663533646331346631
31643638373537653533353036653766663935663636663561343239383666333661343830353133
34363363333466393761643863393436386231626134663236326335336438633338313963646363
30623262386437313733353038353231353163326133643139633963303864633739383935363664
61336265656666643037316139306534323135333763383230633261336139636362396539643539
34303937656634653862383665356530643064383832363163343331383538623236366535393061
38373738393064376539343837356335326132363135323935333964383635383965656462383636
63663661626632396663383838353633663839303936646537363266346661373033663064326435
62646130376163623363346232346530376638613934623831303636366365313331613436626337
61346262333933363366653166326330663638643230373364653161333263323035366263623330
66636532616234636263323366626432363337326564663531323663356166303930653661313030
32363133313162313331623138356432653630663263623935303739663363323130646133613735
66333933393266663265333036616465353338656664313230643761303439363035663566393930
31303633396665316330623962643439313132633531656362333630653537393061316663356566
39376230643830333035316439346336313464623238373739623636313236316162356337313339
62376533663138613962306331313066383439373039636631633431316232643266326361666134
64383437636561323964346134663032663466333831663836393039353562663065643337303330
62356666353662386439353563643735633730613463666263666539323333613130633765393834
32343439306636306131386537373164363636386330623534373535323631396464626661323361
38353935623566373834643661616631373333303735393835643737626234643337653130396365
65666332323665356330396238633866653761346531303439666236653264323661626135353238
36643562623266636333623831303439336366646133653332313130336436386537653234666435
31343863376233623335366333363232653966316230363836613231613130613166643864373565
35356264383335623539643630323534623265313631383130643739306533663330396434653236
64376166373639363731663437663331346338373539363637353933386239373738373565353030
64353261366232643061356165323961383537626239623732393936623461393961353837633733
34356166393938346232396532353166373534623530646335633338633636336636646630356561
32363061356632313661386535306339636135623834333231303433343037353633613365326333
37666235323239383661323536353830383833326565346564663631336465313664346533323337
38613961313233623033386166336235383362393463393832646538373139333533313266303937
62346532356632316136633533373665373839623336383435353163386531366466646664326565
30303639393933373361623333326432366332396137396238336464376131323631343637306531
37343933373139333333623233386334636436356432303764653235353133366566383031633136
34616133336663623664616432336265323534373163316338386561623864623861343835633062
34343738616134366164356337663566326462303933386139643734376332313066613230326363
66623837323238356366333836386662366435626236333835346662623631373636663033623733
38316639343638313937353636616638396261333561313032383130393538663366636630376539
63353566613835343964356635303939343764396631393738646432313765666564316363626431
65346637656137363266346266616666316361383231343666643063353131386163356638346636
30383932633264373031373935616230323933373863663564363233313232363066326662303165
63346532313837396365353365636663313334626433303732326164363330303438636333636163
35656537623165323666633435386465303063633534656630306664343637336164626433373361
65376530333361303337623634353434373164626133626263613561613436303161626432626239
37343536313531626233343530633634613166633735613233393962323165623166366161356336
35386635366631326266343432386161663033323962313763343163663137643631393166333031
39346564656665343835616464663231333562616661643234326663633563303964386131656363
63666363356562383830646633396238623537336439326162376135633665653165326536353037
37313362666531333837633439643165356534383265643637363933366463343839333961376235
63333063643634623735363233646334633235373132646139313365303336646264633061643131
32616465633131356130396465643235353530326564373136313133613064313562306333313965
38396237653430353533353462373130303262663564653361313465353934353864656235653135
34613639613633633234386639633230653537393965323363623338656465326531346432333637
64343436373436356535333865643865373539393036626137626538626635653637666362356162
30313632396539623962346562646563316264613232343730643565386135346664646363333330
66656661636235633730393063343634636138383264336535326533356231626530613565336161
35626232343436616535373230653039303065343432343738616363626635383364373266323333
33376364666638313564366237356635653731623566626661373961663736666638343061646134
35313438356531383433636565326365313063383834613837666330396331353738323237363333
63363963666465313137386537356462663636323737306362326362363266343062626130616230
64363433343738343632636633373330386464396364383031343531663432363563653032336332
65366364333133386139636165303964366165326336316534323636633462356335633066643165
34613030323234383965396233373333393336653237613062323530353762633931343333323865
30663862373132633834353039653032373737313564333638333762303335636265646162313931
66393662653933363832623061633634626661356437663331373937396631356131333462656666
32303166396533643261646130306161326561326533626531663038643565376439633339333432
64333437366566666366303230616539663564333463666631646163356235636333363633663639
37666332346161376239656137306430623463653466626663636539666532373565373731613165
62663532383165656432313762376235333331343738646532373265353066363262333261626137
31396332383963353066336666366133336138653363613863653833653964663164313831333065
35333738383232656634356564643634346633313137333863363766643433363631333630643731
65363161303235323830376638303135613630663362653566363965313436323033643366306630
39303935636639333961666135633962653362666536663333623430356164376262346662643635
33323663333832316633373035386334623134326536366236636561373635353366386237323933
62393435363235396262653065656562383063663236323134313833363833396131643533666235
37386366343933376338336533316239383430343566626434303537653431626261363438336334
35363961656332336230386535386531363761303766313563333832633033646461393635376339
39633630336366373663666239623030326331346361323132363565366366616236346230636632
38376534363933383965386338313835356135663035326536343532643930383466633538316538
31353038656533336335376265626139333364633537633662653362393666346163386431326261
35393261353230373034633666663638306134643066643533323761666264326162343630376661
65613733343866306364333665353639646263323863663562333965636335613966323564373535
39363939383031393265613035376635663962386530663639356331393830383130626439346666
31393532316431393666616535363430636637366134366636643730636431343034336539616135
38633063333063383766386265336363386362383136653536616663376463333935356162343930
36383831666537313936393033363738666335653739646431363039373939626538343037633631
39383439373336336561663431626265666434646565356438336530643863656464323034353565
36366563323836336162373465313938646239373637613066333238323533346338353834636631
30333262376638336537623466643736653562336336663436333963366464666131303862313335
61353862656435653939343362393934303633303333366231646431656234656638613033383133
31353262353231663633633063663537353536383138366132646364353661363135336333323133
64613231626662666364313232333633386265353935363065333933666165633862393965326637
63623962616164626237303466623565623032666431383633323233633861326132346263386631
64386364653633363965356664636434393031383663393137343733343732363239633436663636
64346237653966363538303632363461663030396237623661356438653562396232313935626164
64326162363264323831663965383639393937613931663239316663323164306537326363376339
33333063373464363065336132613230643831303937373163386263646562313361306133306639
36636264373638326663613236353439383532323032393431373333626330313235623362643137
30636462643536363638613936383931363663343964363038373834343164633062343265666137
30373734396232343936326330623362316636616535643136313765356439323934386364643631
34316630366332366432373739363637623437363132646330326361363366313633343634383132
34626633343163613136343665373931363065306232313336356461373366623934306563383935
35373930633334343864306165653034386133393636386662303737303136613432333531313461
62323065343037386231656335326364363761396532346661343664636637633334383131613833
34306465643133383239306534383035303363353766613631643464383264656536323866326464
38666665613166653638633039666261326135363833393832373564333765353134636138343266
64373536313666353332613535633061363835363839323430333430643863343461643236333937
62346262396331613536343539653766323561343639643766653535353335383736333464613331
61336337613737356236636333393236653263663065353431633537666161373638663861363863
36393364616566343561393364313531356134626431646261346363343939616332313631636331
31393435373265313836653533323237613336333061306330636665626233613537383932316235
35646633653664313834376466306335653465613866393939323265316436333062646662656462
36313861306533326163306266353538396436386365393464613335646432366461326331623664
35616665666337663163663631393539663731376333393339373065643363326535643563383532
63656466623939376632636433316661613730386363363930613830386638653837323938373030
34653565386564333866336337316164663931396630333634336130383465643061633239656638
66666166303835326365353433636130653038643938653365333431646561306536623037666231
30333830376637653932613961353931363537336462643030376537386539623636303038363862
34373036393931303465626563623664663532666166336334653234346561303538313036343565
61363734333737393131643661326331383036333363653333373536373134306436646139636561
61386462323832653061313034616532643265343636313366346537356164346461313436373637
34316663356135636231613330323431316566323361363636633436653864633564366366383339
61633266343336643430623138326436383361636161326264346365643536343838333138646563
65383230373361663461383236313832366334303632313935313263646266393030313238613334
66626631323033383334636561313666653165356135366435613438323662353135633234346662
33333336646166643862396361383636306431353439333562633533303265303266613662306162
34383062333166393739656365303738373361373436343064323636336634353232383232356334
35633561383735316663383333303334633631346339323562353634396533343636653963653462
61393039303366626563393737306336376437666138393562373933333335633435396632333232
39666435383832663462626563646162666565393530393164373963386161666436343263316639
30343064663133616135613164653937366636353062303139366261313165373362643365316663
33653630633732623466343236646136663730663938333234613163663835393036363161386332
62383833396164313132633535323530633937626437383462663866346163623234663564306533
65326362636433333930623663653031313438363930373462663639366434633665656138303866
35626333336532346663366530303061343835376239643466326361613030613730326130633165
39333465393466336231333335616662386238346537633164666636333133306266613064343165
39653963346133333234353266323065656237303233623264376233616334623665323433623632
63316262306337386535653233336635616438356565343433393662653036663736663663666435
33333433343566623331333961613662306236386439386135653138333638366566313534383934
62626261303530306237653637363933393634663330336462393932353230313730336362376134
35343530363431323366613361643636663961366238636537616237633965666639633265376437
63363930353064346664323435313136316132373237356332383537623032633831353563326230
65626166336166363164613130393165356139353439353436666537346362326635386136313464
34383633336636376137643733313637373535643966376435353339363535653139313739313362
65343434343364666639306663663665356533323635316534316561313263663662623764326138
38386434316535653262616530643164663335323436386365313361656430616535346463643765
64613231623333363835386337643334333039363835343731316165346438363234666134343263
63663036663566373734656661613432623761393964313166393532396664326230363230303161
36373364663137373234383134363966633935666365303430343539663461623561383236626137
66623964333766323534316439643666323666336539393566316331363862666561656634326166
64383236633638663163666236633531346330643066353566336337646265623361326261373862
32626538316631303465396436643236376161613232666339373537383438633630316365363065
31653433326333613431303936333137323632383163323561313636396331376664656365326536
39323632623861333466333530643864616166623261346237356431326335343431373164633366
34363932656234613431306135323434353164323461346262656337336137616430386533313933
65306566373634363933616233316562643930666161643234323864336631343032326462623365
65363036633061643463343637313933396436636333663861393333353732383736633534303864
62376339343938383639626237373961623931616264353264353337333133396564623831643338
39653962623766643239393061643938643066386564613932656565306564303066316165336230
62363330653137616666343333323636663462643264656364396138626265623964663730636561
31356339323934366637623165623039323439333434653336623962643734653436376462386232
64393863353164373734313262383638393961623466653034626666353361393230623933373336
35323661333330393835363064396564613766626665623866346334643463663865323264386661
33663561616131616134333564343334343765373061393131376231653536353163643435613564
32376466363230363930393734663433313133646238396366356361663636343362313237303766
63613538383836646333366664313637333537303333373537646130393631656636623461383533
31333661376236323736666136393062643566313131383165663965656637303634366330666539
61336265356662336236626432643738343038396263393665396337633837303761613332623436
33313235323938333333666437613731376562376233353664313362356433383938376436373863
32633131386462333838323536333439323733393266376632386530366363633337323963353437
37653334626434616433643930363765366439613236373731343339613237633962356531303433
38333261613062323963366131633738613463363364653531663639626234383263633963336635
65343330636330353363356134363138333031393838623635343335393462343036316638623861
30323638373032653331616361383338333761386264623435656561623337303863323536633932
61613964363538313435363231613834323333336364353962346265646233613935313632343738
65303732376561643763336162333962353136663136613466666631323063646432323130616266
65663431626562646537366661393638346538336538666466343261396431383232356238353062
37653031653766333931393763346366356563393261363438363535303163303962306630306665
62346633356463653465363965396164323437346132396138316562316237303033396233636336
30623039326132393534633937623363656666663366643130633161646566386135303939383762
33356334636565643761323638346162373636323433306436303331336432333830623739643237
64646432366466326139306663356438613433366534616462383938646239643262373836363032
61623735666238626435316530363833366135633563663530643631623539333832343561323138
32383138303464393265373665333736303861646464373861613730653861353463323837383737
30356437653833376631303636393739636663663936656663393130616637303332393636363431
38663837393231326536643033376663316138363234306637613135396365616636656236646335
33633962626135343564633337663936393031316133646334303635653130626131646531396134
38343631613562393435326139366330373064393839636138323466646533303538

View File

@ -0,0 +1,100 @@
$ANSIBLE_VAULT;1.1;AES256
66366138323934613133623237633539616236326462373461303832393739313466373236323765
3461353265343631356335643139363335356262346238360a383136303237393662303762393766
61346362386338663037396631633932373834303265383662356539323766393466656564633465
3835623862356266390a646463633764653431353537643265363764653934656430646363373335
32343135303266623365656532633061373564623664616564343638636138623433363964303366
63323939396365363539366562626135626662336236313963613233633637313731313465363636
39386237393034383263346164623036646535623463306330663034383632373836333661666435
61656662353762653266363036373430343333653835646365613835303935396230363032636164
64613730663339316261313664633636613763313631653839313465336562633663306563633561
38613661333766366633333463376162306365323330356339613266326331353866316638363237
33646165313865313431666163613234366133616263396630303362333336323638373131396334
39656534616331643530646530316335633730323166373830353262366465306631636339316266
32303162313438373531616439356563303030383136613531353561316234353632646232396433
38643463333836326435303733373239626562363264653532323334356262346133633361373963
64396564313630393164323231313937643435613234376436386563623435633666616331643530
39366536616165303562663638313739353763656134316132616162303161623130616263306366
65613264623935333134383733353637653336636532383165646338303633353330623231383239
39343834643038656539623162353561646364393162323839643533333363616437393239313034
61356134643031356536653262663833336361653632626364336565616163376238326334663661
35623338393730636237616161383032353762383965633962343330353235643363346633313462
36653365346263323062653239373132323734626363623337393635373738663931656363383136
62613836356562363866623436393131323130306636356235343035333534326331343337383431
38613565383365666632326238363165313631373262336234666434313065363363346636653339
36363432306639303266366665643934346562663934666665343030396233666534633438396332
31323662363130616338333233373961316639633436313737353530646135373533613433353034
62346432623261346334623738663835666639616564373961643439336432316365666665393135
38623936616361313634333339353133633165663936616332323938396533393235636435376439
62633537633136386366313934373263383730633334343636373035316638343334356530613530
63396438343139383439666539383531386437313865303864316437363563663065643266353138
66323133646463653066323466653662653736306162636565326663386362366332303761653564
31383133396131663563343339623563363239363763643530383833353263646264363565656535
64343737663261653530623836356430666462633964353832663964396462363430623336646336
65356566653938376132663230333033376261376538306266643565613561373636383532616139
30396564613564333964303262656162313839663435666539393734376639653562643735393037
34613864353764303661653561383466663730333932663139616164333239633961326632346230
30316138626562346434643033303333333234396533626633333437316636323062643035623664
38626434366261326663393839343765363133623339373738313563653736373565336164356435
37623837343437623833623137373662653934363133633366636436663831653737376631376431
34363461323535323337343632653430333961343165633864346132343938313361373864363565
32663734626631323930613638323133396135313562643536343038366233373136653330626239
65313933636136303365353466646533353236343934356330356161343433643139383764393134
32356331653831633832376262356238336634353362373837646563653835613634356463653466
30383361356631616538333565646435656361313839346165376231643633643634313863663137
61333236313436383464663439366637643663356535613861343831663737623364303339643733
36373461323130333639613235373961313736303436666361613134323265386165616237393164
34366530363034376437393866333861646636396434636631343033633565396164663833623331
32666161636163333266393361383838653333326437303235326565306663356366613430303237
65343937653439353334343834303234643136656565366461393838653739336233613234616437
62643065356462306565363964663332663564313734336239633833306135613662633535666662
36616639323332353864383733393561666464313466393535373961613831313463306461663266
37653230663732393061616365656638623830346536373932636461663532343532366566343436
63376365643061623839393139333661643439376363396564363237346461393264663131616162
32396464363231613231363561373334646362636536343732396364653132663664366434313538
39396262333232383934396335653461346338316564303563626363646136633266393937343434
34396234363362336232653136666639613466663833303062356264633461643932613162303031
33663539366332643538353632336433393564366565323034393531626236353432623531383033
64613435623761623562363563323364396166353265363039663932626431666339376632353539
63656330626438653366396635353236663762666439613237623638663731306331313564333239
37363663366134303037376433323735366266613831356635663932626162343639306366386439
61643831336139303133336366366165303934646362303665643135386462353565303932383930
33393334353235306534366339613066633434393038636331366265336163306334323638393264
64313538316632373430656532623532313063613337626165353365303832373566316131666336
62353062343565633836306235343134323433303633346130363362633263343564616535396263
65666666646231336636616364646565303538343361653932356135393161316335343333653439
61373266633033653931623631643430613137393633393063353833306463663630333434616462
33653230613639616531666335336131373636323065616239313733323664623138313964303930
35366665626362303161396562306639613435396331366363616138613735383030366362396337
66356666643131393433343237346533383335376462383566643035616438396366633737393133
66323630656539363237646663363764363536373266383036636166333834366663613863663533
62393235666666653433613665376431306439616138633533656362323436613231303264303764
30336665336661393866343935313465626264303139353632356137663439373232326339393136
64306365353639626565653965666133346364613538333135653831663032613135653263353965
63373532323062653630646363323063383065646562313539373637623463313333313535323866
32363631613035653637663935313535626333333433623735663439383239373231613037303736
39633436383361356633373037333362363861346263313038373131653938663930666538306432
34386163316163623064376132653062333535396631393363393265303964356431663439636234
64636138333031656364656565346163663533353333353666373466373734633263626439316230
65313031396564613163333364376637303539343563613133613133376239623066303139393866
32623135396134396439653061386561666433613536336566613530656530333433343537623866
31333364636631336264636531343365633264633433643661353164653831343836323763343033
37386131306563626437343034333330623932303639646631613239303331646364323465616562
62353030633765393237653161636165363465336136333264373832616537356531313066643263
38346331383061373133353132646562313630643335376565396662653830656538356165356137
31396232326666613236313961636334383962373533613566333930313866373334613064376561
65313565303630326531613131316463386636623830346131656532363632613032303466623334
33353633663730306638623566326533363065663363373537353130393938313936383763663966
34336535663565633162313732376237336463343833303939353965653665356563326534643033
34343638666463363462363235343731346461336235306264643866366235663961363461373930
63326334323363656263616531373861633936636339623835323936373661373364336233316631
66366462643663316162383438376162663065633333353138363836353331343162396636623130
62383461626534386664633166323764303631373731366133633930643232303934666535393237
35373462313561353561643866623761313839316662373134363431373562373062313430613462
37333635313037656433656363313864653037313732656232323639383838326263323564643263
38373337353635353836366136326334343661393064316139373431313330653966323763306337
62333066323961623535336232303234636138306630313732373364613363663434633734346231
64663930633162313937343130343961356437353366306338663636366631326366663938363531
63353863306137653237656330656237356563346337343262363664313339323863616438373537
63643235306137363264383238316434313331336337356364366261313835656562643566666130
633536646634326262663866316566376638

View File

@ -0,0 +1,89 @@
$ANSIBLE_VAULT;1.1;AES256
32373237336239343336393066383464393861636235623430343533636365306430323738643234
3538336532623734333038333832393735343363363566340a643638636634653735656635336338
39396461646661353061373636313032333065373562373036336232346133313334333862353034
6337653431323235650a663536386561366531623363303963353539326339393034313961393362
30306235623461326365646365373835333235303965336635363361366336303236333237383539
61383438316464336338633163366532323435616563343463623266346632393930353332626137
34396538653134373433333461373337333639393530383738373764353731363264373835626364
35393163333462343562303136313264653764333038343838656562653133353934336666643534
63366264393462643065323865303033636133663164366334313564333262633736626263363338
39376164343330666332333534313634633137653432343232656464363066356336623166303030
34653432366563663432343164636665373139346435396135303736653030653930393963663538
36333636623832633630386235623365363065343936363031613165383534353837353231373164
37373038363361633330653633396562323738663739316634666137306161313233633561383064
30323236643635663766393862343363653866303431346535626565356162353433623132363031
62656332383835386136656534636135346234326561623037396239303034353961396134396334
35303463366439363336363666623064623564323032646337366332666536373064353962373461
63306166616535356231396566316433633062376164303434323639376339643731393461393536
65633363616235343532386435323736313138666661666434643935623266323133336463326532
33326364346364626165666262396133343736656335353732666362613234343163343465326361
33383136636364383466363666316131383366623665323561636130343337613539383134646535
31383131623237636433313133336162633537653533383435336461616439343035336164333363
31623638333465306538313637636436626132656534313064383663393230653132333938343537
65343339333037613332316534336133373864666130303166393038373531396266303832383632
65343531616661303363303966303230353630356437336164383038366563363166363763396464
37386330653563613063323438363737313565363130353264613236346565323837326631363935
31346365653938653566646437623333326533646235343966383031656132396539616661393461
65333235306432666539623964393132616436653430383236353033333366336363323539333636
64616563376464646534343838616437306232393262313065353936356235373231613561323866
61383536636361363039656138306131383732326464613931363837376234326433376533643861
32616434383536373532383238663263643862373738333338343332303735663863346331663037
35643637356531323639623533313865656132353139323436363661643263323633363161653235
37636635623865303536353264313263373938366165623364643337313831653161623231343764
33386162623531396234623937633465653930636637623837653138373365346132323731346130
64613338386662653833653034313066636566333839306539666161333333616261653537313363
64656632333462633232396236373666366464623464653434383832333365376532626531313735
30313335353664643566313437393834393262333665666366326463663761626135326434363931
36306439376138313838613532343663383938366333316432303930326239646232623633373564
62316632383131626432333461323330366165366331303735333330363335366265316330663563
64393231393136626162386335626433336337373765623933346237643532366662616434366163
37373832303664303836373434343032313731323362353031346438643335323131366538653334
33643432646339383865386238666134383861616437663238366365663737623663323137613865
63633965323933366332363131313834653564636336303966656663366361353731316336633233
32623339343838373639343534326365346135393137303736346634303863333664376332636634
30303938353536636365353338393932353435383635326435666133353430323464333531356563
31353733323331656538373932643332316332386437373938373635633832383662316537346132
35316339343538343462363237666332376461363262623438623738623732383337373738346235
64333335396336333337643235616436373736623339366236313938653433343661366332646265
34636530666636363764366533643739653561626134393936616632616264663230616164376132
30656336633230323535653766636361626562306262326265626166343036643034303730306164
63356131333739333338353835363430363864333063363238303861323033643534366264623433
30653639633862376232393065626636396137343635343030316630313863323365363764616630
38346336663932626430613437656437313462633039393934653532386535323836366465383761
39323732666339386565653836323461623238316564323333363461396161643338633137646335
66373461633233333337663332323064373662636535376433613232653137353834373630663366
61343066303366666362353837343337386631653461646230656533663965626135383131346635
31623131653264353861353630646662303835643738323565383233336334356264353939373933
31303964346563636437633532383762383234303130366331313864386330653130653437356466
38373135333066336139336332643666373932666565303062636465326236623963323337633634
66646633366532646232326435663065393035386438343030323038663033356639356264663532
61396130643135666266366664323234353065303031343531366532633532363534646536646235
62383531393832643137633332353364333230383361663264623564366539323132623639623939
61323263373866343933653734323661383634636139383833323837303236326364666466386336
34316465346261366131316535303563623238346530643264326539653432633237656133613532
30663738313139333461346163626130343535306538623763343134623832346132656666393761
35316164646635613032326565353163656134616366386364306436303134386339346462653262
61383961656334653564623262366265316364366538353362313233343239396265383235303534
33666366323466303534333165653334343437316435613566326338666336326664616133313062
66333339346335626663323335373939303163623331303133643937653362666430323930623462
30393239633763666463643066393161353235386461633066306235376261346139363330663235
31643539616335396331656364383265346333323661333066353732653336616330303931376164
37643931313337646337333236323939613333303834356662373836633631393736616462363338
31623064303936306330343361313763336239316362633732326564653566313265616566336135
61616538653365313666613366313064623232653563383465386535636530643831633735323433
30353239333166343366643738363834613230316463636339666434633961386335623238353030
34356536376164613338376534353438383039383930316439653732643339653531316530393534
35326165666439396537396464656339333366333535366530353064396436663966333465616630
33666233313537363165333738393362656631386564376365616266393137633931643833343232
62393663663836303563386235383363623966316635366133353165346635373063383666373833
35633264666139616463333339653733376431363761653433653138356364383865633937363433
33313361653536633066656164616331343033373339336334666635353630636532323632323261
39303937626633613434653835376538356164396631326163346465663337386230656139396237
36613762346462626135323233393537616539646234663866353433396530383966613333376137
37373461333561313966303239633834663837656230613830303433353639643431323930633238
63383161313938663737396539663163303161633732393130363737303732313166623534303339
65323162386430393639303435653436656239303032663761626462633565626161656632626162
62386631316434383239303631343536363034626663626430633635353933313533316337613532
33383335326637626535336664626663376332316236633735663339373131373630643665356133
31393664663737326638

View File

@ -0,0 +1,58 @@
$ANSIBLE_VAULT;1.1;AES256
65656166313438643163366632316530386139623538636439633638636566383566646239306131
3938333565313734613639376539323233353932373635640a313831613637383734636539666463
64306331656564626233383831633862623861346364366632313733623263306464636264363965
3933326435396164390a646439366537323232633232373339343538616431343137373338326166
65373365613465616631623463313364396332366539386462333737623737343330393662646533
62353663306531663935623765353838333138346630313333373066303835323461383630306662
34316363316661613865616163393133626139663162393336356665373465353766656661633731
37373563396437366661373134623664393430616532353530303861336238666539306562343662
32613431393331306234643362323961343261376238353635366132623638663463343730343730
37323733313739636238376538323264333238643532306439366463626233613237313933383333
31373064343036616239616562373264653163396265613935656638613662663364633866393638
62303563363763356433376634626234663234323636366232616431646534383730346233333963
31616263353462653932343537343863326337643037326265666433623965646264303066316139
31653864383331626231313736623563316330393563376562303933313237383939396438623231
65383666336565393236326433646561346635356661356136306165323432383531646264323064
31353738663861306135636131333261333964663338636637306665333663313164393537396663
36666663616634323137333835626133383737666632316336313661656434376239616437346636
62643035376637373031636330646638356562643962313336653964616337643064346562366531
33613935656630633736386632616162663535366466663637313339323939646136636165656166
38346562346331323738393934396362316361643538653163333935656139356535363432313532
38633336646332386661643464666263646432373134306639306561663134373164326632613531
64313162303263333534666436333634663262623632366631633865336433303564363138353566
36303862656531343765643965666531613231343035636537373030613932303039623131363830
37346263666637373639643930303438316430663462333430613335613131396566303533343864
62373439663236636232353230343433336137613930623133303936323562313061336637306566
34383336646336663263373334323131316262613136353239616630303264633238383266323464
37623864646331363735306132393936306162393463313736366166656439343039626434353739
37613532393830323431393964333437306366313335393434323463346133343237303732343962
33373164363135363335323435636666386231363463373864663933373430656239366539643164
30323038323739373965616630336166356362653833303132336230323661373737666232346630
38393933303736306537383364356162656339613461333262656137636662303532663737636237
36333661663734643363636661353337616162396666356663393432633361313534333537393161
66666165363635346162623965333061386563663166643736653134303638613332313637333064
65333438333661343664303361316631643763323164386330636139353932646635393963656336
36343362323332336130633533663234343236393639323062663962633336626435653137306539
63633866616438623764616631663533363233346362336132303861653039386133323965643863
30633932646132633862666266323761656438343935636332326263653437333366306338636137
65303538613661373538313437646466393536313665623666396235353962306634386261396337
61376439636531383631383234313230303731653435393964393835393236653739316634623363
61363730333632323039326438366633336462656135366164663434383561356337393636353661
64616435386238316265386565633938623935663332633062316163356337303765366262313534
61396361326333616136366435666662346637663864326561653634313030303033303132366132
64353635383932633733303333636137323237393764396136313661353463306137316563303232
32363063626630343230333065376638626236653532383766363161313862616336396334303764
38393262613531343134653130313237343036383464393739353631636235343930653537373935
63306431643132643362656433313061303838306164643236316166303331313636376431326239
66386635333631653232383664343864383739663364363131373062623835363635393930326639
33303733353761336638363935316232336533366339396166383539363963373536346232663865
39613463386138363364316365373161313130316638616635313235363235396166323935353664
39646163306161323536366532333231373530636234643764366134306164333431336636333533
32333966393634393135333031356533666531613262313432346366373262373565323962323939
36343764303866653638336134653263616561396332643030356434383531343166356466646633
37336564613131633534313064303933633134393131656536383439393633366164376636353634
34663236663163633338303838303733643262363834633064313532626631646239306564313361
62616331306330636366306633366430353964376466313032356434346532366362356136376536
33613962316539376138323033623736366531643261386535653733303465333331383131666530
38336561353633303639616635656566323130616561656235393135616631356334

View File

@ -0,0 +1,6 @@
---
- name: restart apache
become: yes
service:
name: apache2
state: restarted

View File

@ -0,0 +1,96 @@
---
- name: Install apache
become: yes
apt:
name: "{{ item }}"
state: present
with_items:
- 'apache2'
- 'libapache2-mod-wsgi'
- 'cronolog'
- name: Ensure apache is running and enabled
become: yes
service:
name: apache2
state: started
enabled: yes
- name: Create apache config
become: yes
template:
src: apache.conf.j2
dest: "/etc/apache2/sites-available/prod.conf"
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0664
notify:
- restart apache
- name: Create static directory
become: yes
file:
path: "/var/www/static"
state: directory
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0755
- name: Create WSGI Script
template:
src: prod.wsgi.j2
dest: "{{ project_path }}/deploy/prod.wsgi"
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0664
- name: Remove apache2 logrotate file
become: yes
file:
path: /etc/logrotate.d/apache2
state: absent
notify:
- restart apache
- name: Disable default site
become: yes
command: a2dissite 000-default
notify:
- restart apache
- name: Enable prod site
become: yes
command: a2ensite prod
notify:
- restart apache
- name: Enable SSL rewrite headers
become: yes
command: a2enmod ssl rewrite headers
notify:
- restart apache
- name: Generate static files
django_manage:
app_path: "{{ project_path }}"
command: "collectstatic"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
notify:
- restart apache
- name: Migrate databse
django_manage:
app_path: "{{ project_path }}"
command: "migrate --noinput"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
notify:
- restart apache
- name: Add unglueit log file to www-data group
file:
path: "/var/log/regluit/unglue.it.log"
group: www-data
notify:
- restart apache

View File

@ -0,0 +1,67 @@
---
- name: Create celery user
become: yes
user:
create_home: no
name: "celery"
tags:
- celery
- name: Add current user to celery and www-data groups
become: yes
user:
name: "{{ user_name }}"
groups:
- celery
- www-data
append: yes
tags:
- celery
- name: Create directories for celery
become: yes
file:
path: "{{ item }}"
state: directory
owner: celery
group: celery
mode: 0775
with_items:
- '/var/log/celery'
- '/var/run/celery'
tags:
- celery
- name: Copy celery init.d scripts
become: yes
copy:
src: "{{ item }}"
dest: "/etc/init.d/{{ item }}"
mode: 0755
with_items:
- 'celeryd'
- 'celerybeat'
tags:
- celery
- name: Copy celery config files
become: yes
template:
src: "celery/{{ item }}.j2"
dest: "/etc/default/{{ item }}"
mode: 0644
with_items:
- 'celeryd'
- 'celerybeat'
tags:
- celery
- name: Start celeryd
django_manage:
app_path: "{{ project_path }}"
command: "celeryd_multi restart w1"
virtualenv: "{{ project_path }}/venv"
settings: "{{ django_settings_module }}"
- name: Start celerybeat
command: /etc/init.d/celerybeat start

View File

@ -0,0 +1,39 @@
---
- name: Copy server key
become: yes
copy:
src: certs/server.key
dest: /etc/ssl/private/server.key
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0600
notify:
- restart apache
tags:
- certs
- name: Copy STAR_unglue_it.crt
become: yes
copy:
src: certs/STAR_unglue_it.crt
dest: /etc/ssl/certs/server.crt
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0644
notify:
- restart apache
tags:
- certs
- name: Copy STAR_unglue_it.ca-bundle
become: yes
copy:
src: certs/STAR_unglue_it.ca-bundle
dest: /etc/ssl/certs/STAR_unglue_it.ca-bundle
owner: "{{ user_name }}"
group: "{{ user_name }}"
mode: 0600
notify:
- restart apache
tags:
- certs

View File

@ -0,0 +1,120 @@
---
- name: Install prod dependencies
become: true
apt:
name: "{{ item }}"
update_cache: true
state: present
with_items:
- 'git'
- 'python-setuptools'
- 'python-lxml'
- 'python-dev'
- 'python-virtualenv'
- 'build-essential'
- 'libssl-dev'
- 'libffi-dev'
- 'libxml2-dev'
- 'libxslt-dev'
- 'mysql-client'
- 'libmysqlclient-dev'
- 'python-mysqldb'
- 'postfix'
- 'libjpeg-dev'
- name: Create project directory
become: true
file:
path: "{{ project_path }}"
state: directory
owner: "{{ user_name }}"
mode: 0755
- name: Checkout regluit repo
git:
accept_hostkey: yes
force: yes
repo: "{{ git_repo }}"
dest: "{{ project_path }}"
version: "{{ git_branch }}"
- name: Install python packages to virtualenv
pip:
requirements: "{{ project_path }}/requirements_versioned.pip"
state: present
virtualenv: "{{ project_path }}/venv"
- name: Add project to PYTHONPATH of virtualenv
template:
src: "{{ item }}.j2"
dest: "{{ project_path }}/venv/lib/python2.7/site-packages/{{ item }}"
with_items:
- 'regluit.pth'
- 'opt.pth'
- name: Create keys directory
file:
path: "{{ project_path}}/settings/keys"
state: directory
owner: "{{ user_name }}"
mode: 0755
- name: Copy keys files
copy:
src: "{{ project_path }}/settings/dummy/__init__.py"
dest: "{{ project_path }}/settings/keys/__init__.py"
remote_src: yes
- name: Copy django settings template
template:
src: prod.py.j2
dest: "{{ project_path }}/settings/prod.py"
- name: Copy key templates to keys directory
template:
src: "{{ item }}.j2"
dest: "{{ project_path }}/settings/keys/{{ item }}"
with_items:
- 'common.py'
- 'host.py'
- name: Create django log directory
become: yes
file:
path: "/var/log/regluit"
state: directory
owner: "{{ user_name }}"
group: "www-data"
mode: 0775
- name: Open ports on firewall
become: yes
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
with_items:
- 22
- 80
- 443
- name: Run redis tasks
import_tasks: redis.yml
# - name: Run mysql tasks
# import_tasks: mysql.yml
- name: Run cert tasks
import_tasks: certs.yml
- name: Run apache tasks
import_tasks: apache.yml
- name: Run celery tasks
import_tasks: celery.yml

View File

@ -0,0 +1,13 @@
---
- name: Install Redis server
become: yes
apt:
name: "redis-server"
state: present
- name: Ensure Redis is started
become: yes
service:
name: "redis-server"
state: started
enabled: yes

View File

@ -0,0 +1,71 @@
WSGIPythonHome {{ wsgi_home }}
WSGIPythonPath {{ wsgi_python_path }}
WSGISocketPrefix {{ project_path }}
<VirtualHost *:80>
ServerName {{ server_name }}
ServerAdmin info@ebookfoundation.org
Redirect permanent / https://{{ server_name }}
</VirtualHost>
<VirtualHost _default_:443>
ServerName {{ server_name }}:443
ServerAdmin info@ebookfoundation.org
SSLEngine on
SSLProtocol All -SSLv2 -SSLv3
SSLCertificateFile /etc/ssl/certs/server.crt
SSLCertificateKeyFile /etc/ssl/private/server.key
SSLCertificateChainFile /etc/ssl/certs/STAR_unglue_it.ca-bundle
#SSLCertificateChainFile /etc/ssl/certs/gd_bundle.crt
WSGIDaemonProcess regluit processes=4 threads=4 python-eggs=/tmp/regluit-python-eggs
WSGIScriptAlias / /opt/regluit/deploy/prod.wsgi
# generated using https://mozilla.github.io/server-side-tls/ssl-config-generator/
# intermediate mode
# 2015.03.04 (with Apache v 2.2.22 and OpenSSL 1.0.1 and HSTS enabled)
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
SSLHonorCipherOrder on
# HSTS (mod_headers is required) (15768000 seconds = 6 months)
Header always add Strict-Transport-Security "max-age=15768000"
<Directory /opt/regluit/deploy>
<Files prod.wsgi>
Require all granted
</Files>
</Directory>
<Directory /opt/regluit/static>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
Alias /static /var/www/static
BrowserMatch "MSIE [2-6]" \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0
# MSIE 7 and newer should be able to use keepalive
BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
ErrorLog "|/usr/bin/cronolog /var/log/apache2/%Y%m%d_error.log"
LogLevel warn
CustomLog "|/usr/bin/cronolog /var/log/apache2/%Y%m%d_access.log" combined
</VirtualHost>

View File

@ -0,0 +1,35 @@
# http://docs.celeryproject.org/en/latest/cookbook/daemonizing.html#generic-initd-celerybeat-example
# to be placed at /etc/defaults/celerybeat
# Where to chdir at start.
CELERYBEAT_CHDIR="{{ project_path }}t/"
# Extra arguments to celerybeat
#CELERYBEAT_OPTS="--schedule=/var/run/celerybeat-schedule"
# Name of the celery config module.#
CELERY_CONFIG_MODULE="celeryconfig"
# Name of the projects settings module.
export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}"
# Path to celerybeat
CELERYBEAT="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celerybeat"
# virtualenv to use
VIRTUALENV="{{ project_path }}/{{ virtualenv_name }}"
#Full path to the PID file. Default is /var/run/celeryd.pid
CELERYBEAT_PIDFILE="/var/log/celerybeat/celerybeat.pid"
#Full path to the celeryd log file. Default is /var/log/celeryd.log
CELERYBEAT_LOGFILE="/var/log/celerybeat/celerybeat.log"
#Log level to use for celeryd. Default is INFO.
CELERYBEAT_LOG_LEVEL="INFO"
#User to run celeryd as. Default is current user.
#CELERYBEAT_USER
#Group to run celeryd as. Default is current user.
#CELERYBEAT_GROUP

View File

@ -0,0 +1,9 @@
CELERYD_NODES="w1"
CELERYD_CHDIR="{{ project_path }}/"
CELERYD_LOG_FILE="/var/log/celery/%n.log"
CELERYD_PID_FILE="/var/log/celery/%n.pid"
CELERYD="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd"
CELERYD_MULTI="{{ project_path }}/{{ virtualenv_name }}/bin/django-admin.py celeryd_multi"
VIRTUALENV_ACTIVATE="{{ project_path }}/{{ virtualenv_name }}/bin/activate"
export DJANGO_SETTINGS_MODULE="{{ django_settings_module }}"

View File

@ -0,0 +1,13 @@
import os
# all the COMMON_KEYS
# copy this file to settings/keys/ and replace the dummy values with real ones
BOOXTREAM_API_KEY = os.environ.get('BOOXTREAM_API_KEY', '{{ booxtream_api_key }}')
BOOXTREAM_API_USER = os.environ.get('BOOXTREAM_API_USER', '{{ booxtream_api_user }}')
DROPBOX_KEY = os.environ.get('DROPBOX_KEY', '{{ dropbox_key }}')
GITHUB_PUBLIC_TOKEN = os.environ.get('GITHUB_PUBLIC_TOKEN', '{{ github_public_token }}') # 40 chars; null has lower limit
MAILCHIMP_API_KEY = os.environ.get('MAILCHIMP_API_KEY', '{{ mailchimp_api_key }}') # [32chars]-xx#
MAILCHIMP_NEWS_ID = os.environ.get('MAILCHIMP_NEWS_ID', '{{ mailchimp_news_id }}')
MOBIGEN_PASSWORD = os.environ.get('MOBIGEN_PASSWORD', '{{ mobigen_password }}')
MOBIGEN_URL = os.environ.get('MOBIGEN_URL', '{{ mobigen_url }}') # https://host/mobigen
MOBIGEN_USER_ID = os.environ.get('MOBIGEN_USER_ID', '{{ mobigen_user_id }}')

View File

@ -0,0 +1,5 @@
import os
{% for key in common_keys %}
{{ key|upper }} = os.environ.get('{{ key|upper }}', '{{ common_keys[key] }}')
{% endfor %}

View File

@ -0,0 +1,47 @@
# host.py
# copy this file to settings/keys/ and replace the dummy values with real ones
# or generate it from the ansible vault
import os
# you can use this to generate a key: http://www.miniwebtool.com/django-secret-key-generator/
SECRET_KEY = os.environ.get("SECRET_KEY", '{{ secret_key }}')
# you'll need to register a GoogleBooks API key
# https://code.google.com/apis/console
GOOGLE_BOOKS_API_KEY = os.environ.get("GOOGLE_BOOKS_API_KEY", "{{ google_books_api_key }}")
#
GOODREADS_API_KEY = os.environ.get("GOODREADS_API_KEY", "{{ goodreads_api_key }}")
GOODREADS_API_SECRET = os.environ.get("GOODREADS_API_SECRET", "{{ goodreads_api_secret }}") #43 chars
# Amazon SES
# create with https://console.aws.amazon.com/ses/home?region=us-east-1#smtp-settings:
EMAIL_HOST_USER = os.environ.get("EMAIL_HOST_USER", '{{ email_host_user }}')
EMAIL_HOST_PASSWORD = os.environ.get("EMAIL_HOST_PASSWORD", '{{ email_host_password }}')
# twitter auth
# you'll need to create a new Twitter application to fill in these blanks
# https://dev.twitter.com/apps/new
SOCIAL_AUTH_TWITTER_KEY = os.environ.get("SOCIAL_AUTH_TWITTER_KEY", '{{ social_auth_twitter_key }}')
SOCIAL_AUTH_TWITTER_SECRET = os.environ.get("SOCIAL_AUTH_TWITTER_SECRET", '{{ social_auth_twitter_secret }}')
# support@icontact.nl
BOOXTREAM_API_KEY = os.environ.get("BOOXTREAM_API_KEY", "{{ booxtream_api_key }}") # 30 chars
BOOXTREAM_API_USER = os.environ.get("BOOXTREAM_API_USER", '{{ booxtream_api_user }}')
# you'll need to create a new Facebook application to fill in these blanks
# https://developers.facebook.com/apps/
SOCIAL_AUTH_FACEBOOK_KEY = os.environ.get("SOCIAL_AUTH_FACEBOOK_KEY", '{{ social_auth_facebook_key }}')
SOCIAL_AUTH_FACEBOOK_SECRET = os.environ.get("SOCIAL_AUTH_FACEBOOK_SECRET", '{{ social_auth_facebook_secret }}')
# https://console.developers.google.com/apis/credentials/oauthclient/
# unglue.it (prod) SOCIAL_AUTH_GOOGLE_OAUTH2_KEY #2
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get("_KEY", '{{ social_auth_google_oauth2_key }}')
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get("_SECRET", '{{ social_auth_google_oauth2_secret }}')
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID", '{{ aws_access_key_id }}')
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY", '{{ aws_secret_access_key }}') # 40 chars
DATABASE_USER = os.environ.get("DATABASE_USER", '{{ mysql_db_user }}')
DATABASE_PASSWORD = os.environ.get("DATABASE_PASSWORD", '{{ mysql_db_pass }}')
DATABASE_HOST = os.environ.get("DATABASE_HOST", '{{ mysql_db_host }}')

View File

@ -0,0 +1,5 @@
import os
{% for key in host_keys %}
{{ key|upper }} = os.environ.get('{{ key|upper }}', '{{ host_keys[key] }}')
{% endfor %}

View File

@ -0,0 +1 @@
/opt/

View File

@ -0,0 +1,135 @@
from .common import *
ALLOWED_HOSTS = ['.unglue.it']
DEBUG = False
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG
# we are launched!
IS_PREVIEW = False
SITE_ID = 1
ADMINS = (
('Raymond Yee', 'rdhyee+ungluebugs@gluejar.com'),
('Eric Hellman', 'eric@gluejar.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '{{ mysql_db_name }}',
'USER': '{{ mysql_db_user }}',
'PASSWORD': '{{ mysql_db_pass }}',
'HOST': '{{ mysql_db_host }}',
'PORT': '{{ mysql_db_port }}',
'TEST_CHARSET': 'utf8',
}
}
TIME_ZONE = 'America/New_York'
# settings for outbout email
# if you have a gmail account you can use your email address and password
# Amazon SES
EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend'
MAIL_USE_TLS = True
EMAIL_HOST = '{{ email_host }}'
EMAIL_PORT = '{{ email_port }}'
DEFAULT_FROM_EMAIL = '{{ default_from_email }}'
# send celery log to Python logging
CELERYD_HIJACK_ROOT_LOGGER = False
# Next step to try https
#BASE_URL = 'http://{{ server_name }}'
BASE_URL_SECURE = 'https://{{ server_name }}'
IPN_SECURE_URL = False
# use redis for production queue
BROKER_TRANSPORT = '{{ broker_transport }}'
BROKER_HOST = '{{ broker_host }}'
BROKER_PORT = '{{ broker_port }}'
BROKER_VHOST = '{{ broker_vhost }}'
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'brief': {
'format': '%(asctime)s %(levelname)s %(name)s[%(funcName)s]: %(message)s',
},
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler'
},
'null': {
'level': 'DEBUG',
'class': 'logging.NullHandler',
},
'file': {
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'filename': join('/var/log/regluit', 'unglue.it.log'),
'maxBytes': 1024*1024*5, # 5 MB
'backupCount': 5,
'formatter': 'brief',
},
},
'loggers': {
'django.request': {
'handlers': ['mail_admins'],
'level': 'ERROR',
'propagate': True,
},
'django.security.DisallowedHost': {
'handlers': ['null'],
'propagate': False,
},
'': {
'handlers': ['file'],
'level': 'WARNING',
'propagate': False,
},
}
}
STATIC_ROOT = '/var/www/static'
#CKEDITOR_UPLOAD_PATH = '/var/www/static/media/'
#CKEDITOR_UPLOAD_PREFIX = 'https://unglue.it/static/media/'
# decide which of the period tasks to add to the schedule
CELERYBEAT_SCHEDULE['send_test_email'] = SEND_TEST_EMAIL_JOB
# update the statuses of campaigns
CELERYBEAT_SCHEDULE['update_active_campaign_statuses'] = UPDATE_ACTIVE_CAMPAIGN_STATUSES
CELERYBEAT_SCHEDULE['report_new_ebooks'] = EBOOK_NOTIFICATIONS_JOB
CELERYBEAT_SCHEDULE['notify_ending_soon'] = NOTIFY_ENDING_SOON_JOB
CELERYBEAT_SCHEDULE['update_account_statuses'] = UPDATE_ACCOUNT_STATUSES
CELERYBEAT_SCHEDULE['notify_expiring_accounts'] = NOTIFY_EXPIRING_ACCOUNTS
CELERYBEAT_SCHEDULE['refresh_acqs'] = REFRESH_ACQS_JOB
CELERYBEAT_SCHEDULE['refresh_acqs'] = NOTIFY_UNCLAIMED_GIFTS
# set -- sandbox or production Amazon FPS?
#AMAZON_FPS_HOST = "fps.sandbox.amazonaws.com"
AMAZON_FPS_HOST = "fps.amazonaws.com"
# local settings for maintenance mode
MAINTENANCE_MODE = False
# Amazon keys to permit S3 access
# https://console.aws.amazon.com/iam/home?region=us-east-1#/users/s3user?section=security_credentials
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
# we should suppress Google Analytics outside of production
SHOW_GOOGLE_ANALYTICS = True
# if settings/local.py exists, import those settings -- allows for dynamic generation of parameters such as DATABASES
try:
from regluit.settings.local import *
except ImportError:
pass

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "regluit.settings.prod")
os.environ['CELERY_LOADER'] = 'django'
{% for key in host_keys %}
os.environ['{{ key|upper }}'] = '{{ host_keys[key] }}'
{% endfor %}
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

View File

@ -0,0 +1 @@
{{ project_path }}/

View File

@ -0,0 +1,18 @@
- hosts: regluit-prod
gather_facts: false
tasks:
# Need to install python2.7 and pip first so Ansible will function
# This is due to Ubuntu 16 shipping with Python3 by default
- name: Install python2.7 and pip
become: true
raw: bash -c "apt -qqy update && apt install -qqy python2.7-dev python-pip"
register: output
changed_when: output.stdout != ""
- name: Gathering Facts
setup:
- include_role:
name: regluit_prod

View File

@ -0,0 +1,6 @@
---
- hosts: regluit-local
gather_facts: false
roles:
- regluit_common
- regluit_dev

View File

@ -92,12 +92,12 @@ wsgiref==0.1.2
xhtml2pdf==0.0.6
#for urllib3 secure
cffi==1.7.0
cryptography==1.4
cryptography==2.1.4
enum34==1.1.6
idna==2.1
ipaddress==1.0.16
ndg-httpsclient==0.4.2
pyOpenSSL==16.0.0
pyOpenSSL==16.2.0
pyasn1==0.1.9
pycparser==2.14
setuptools==25.0.0
@ -105,6 +105,6 @@ urllib3==1.16
beautifulsoup4==4.6.0
RISparser==0.4.2
# include these 2 for development
#libsass==0.13.4
#django-compressor==2.2
django-sass-processor==0.5.6
libsass==0.14.5
django-compressor==2.2
django-sass-processor==0.7

View File

@ -45,7 +45,7 @@ MEDIA_ROOT = ''
MEDIA_URL = '/media/'
# set once instead of in all the templates
JQUERY_HOME = "/static/js/jquery-1.7.1.min.js"
JQUERY_HOME = "/static/js/jquery-1.12.4.min.js"
JQUERY_UI_HOME = "/static/js/jquery-ui-1.8.16.custom.min.js"
CKEDITOR_UPLOAD_PATH = ''
@ -145,7 +145,7 @@ ROOT_URLCONF = 'regluit.urls'
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.sitemaps',
@ -171,24 +171,28 @@ INSTALLED_APPS = (
'notification',
'email_change',
'ckeditor',
'storages',
'storages',
'sorl.thumbnail',
'mptt',
# this must appear *after* django.frontend or else it overrides the
'mptt',
# this must appear *after* django.frontend or else it overrides the
# registration templates in frontend/templates/registration
'django.contrib.admin',
'regluit.distro',
'regluit.distro',
'regluit.booxtream',
'regluit.pyepub',
'regluit.libraryauth',
'regluit.libraryauth',
'transmeta',
'questionnaire',
'questionnaire.page',
'questionnaire.page',
'sass_processor',
)
SASS_PROCESSOR_INCLUDE_DIRS = [
os.path.join(PROJECT_DIR, 'static', 'scss'),
os.path.join('static', 'scss'),
os.path.join(PROJECT_DIR, 'static', 'scss', 'foundation', 'scss'),
os.path.join('static', 'scss', 'foundation', 'scss'),
# static/scss/foundation/scss/foundation.scss
]
SASS_PROCESSOR_AUTO_INCLUDE = False
@ -287,14 +291,14 @@ SOCIAL_AUTH_PIPELINE = (
# Make up a username for this person, appends a random string at the end if
# there's any collision.
'social.pipeline.user.get_username',
# make username < 222 in length
'regluit.libraryauth.auth.chop_username',
# Send a validation email to the user to verify its email address.
# Disabled by default.
# 'social.pipeline.mail.mail_validation',
# Associates the current social details with another user account with
# a similar email address. don't use twitter or facebook to log in
'regluit.libraryauth.auth.selectively_associate_by_email',
@ -304,7 +308,7 @@ SOCIAL_AUTH_PIPELINE = (
# Create the record that associated the social account with this user.
'social.pipeline.social_auth.associate_user',
# Populate the extra_data field in the social record with the values
# specified by settings (and the default ones like access_token, etc).
'social.pipeline.social_auth.load_extra_data',
@ -325,7 +329,7 @@ LOGIN_ERROR_URL = '/accounts/login-error/'
USER_AGENT = "unglue.it.bot v0.0.1 <https://unglue.it>"
# The amount of the transaction that Gluejar takes
# The amount of the transaction that Gluejar takes
GLUEJAR_COMMISSION = 0.06
PREAPPROVAL_PERIOD = 365 # days to ask for in a preapproval
PREAPPROVAL_PERIOD_AFTER_CAMPAIGN = 90 # if we ask for preapproval time after a campaign deadline
@ -373,7 +377,7 @@ UPDATE_ACTIVE_CAMPAIGN_STATUSES = {
EBOOK_NOTIFICATIONS_JOB = {
"task": "regluit.core.tasks.report_new_ebooks",
"schedule": crontab(hour=0, minute=30),
"args": ()
"args": ()
}
NOTIFY_ENDING_SOON_JOB = {
@ -397,13 +401,13 @@ UPDATE_ACCOUNT_STATUSES = {
NOTIFY_EXPIRING_ACCOUNTS = {
"task": "regluit.payment.tasks.notify_expiring_accounts",
"schedule": crontab(day_of_month=22, hour=0, minute=30),
"args": ()
"args": ()
}
NOTIFY_UNCLAIMED_GIFTS = {
"task": "regluit.core.tasks.notify_unclaimed_gifts",
"schedule": crontab( hour=2, minute=15),
"args": ()
"args": ()
}
# by default, in common, we don't turn any of the celerybeat jobs on -- turn them on in the local settings file
@ -420,12 +424,12 @@ MAINTENANCE_MODE = False
# Sequence of URL path regexes to exclude from the maintenance mode.
MAINTENANCE_IGNORE_URLS = {}
# we should suppress Google Analytics outside of production
SHOW_GOOGLE_ANALYTICS = False
# to enable uploading to S3 and integration of django-storages + django-ckeditor
# some variables to be overriddden in more specific settings files -- e.g., prod.py,
# some variables to be overriddden in more specific settings files -- e.g., prod.py,
CKEDITOR_ALLOW_NONIMAGE_FILES = False
AWS_ACCESS_KEY_ID = ''
@ -490,5 +494,4 @@ except ImportError:
if AWS_SECRET_ACCESS_KEY:
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
else:
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'

5
start.sh Executable file
View File

@ -0,0 +1,5 @@
#!/bin/bash
django-admin.py celeryd --loglevel=INFO &
django-admin.py celerybeat -l INFO &
django-admin.py runserver 0.0.0.0:8000

View File

@ -0,0 +1,3 @@
.annotator-adder {
width: 80px;
}

817
static/css/reader/main.css Executable file
View File

@ -0,0 +1,817 @@
@font-face {
font-family: 'fontello';
src: url('../../fonts/fontello.eot?60518104');
src: url('../../fonts/fontello.eot?60518104#iefix') format('embedded-opentype'),
url('../../fonts/fontello.woff?60518104') format('woff'),
url('../../fonts/fontello.ttf?60518104') format('truetype'),
url('../../fonts/fontello.svg?60518104#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
body {
background: #4e4e4e;
overflow: hidden;
}
#main {
/* height: 500px; */
position: absolute;
width: 100%;
height: 100%;
right: 0;
/* left: 40px; */
/* -webkit-transform: translate(40px, 0);
-moz-transform: translate(40px, 0); */
/* border-radius: 5px 0px 0px 5px; */
border-radius: 5px;
background: #fff;
overflow: hidden;
-webkit-transition: -webkit-transform .4s, width .2s;
-moz-transition: -webkit-transform .4s, width .2s;
-ms-transition: -webkit-transform .4s, width .2s;
-moz-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
-webkit-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
-ms-box-shadow: inset 0 0 50px rgba(0,0,0,.1);
box-shadow: inset 0 0 50px rgba(0,0,0,.1);
}
#titlebar {
height: 8%;
min-height: 20px;
padding: 10px;
/* margin: 0 50px 0 50px; */
position: relative;
color: #4f4f4f;
font-weight: 100;
font-family: Georgia, "Times New Roman", Times, serif;
opacity: .5;
text-align: center;
-webkit-transition: opacity .5s;
-moz-transition: opacity .5s;
-ms-transition: opacity .5s;
z-index: 10;
}
#titlebar:hover {
opacity: 1;
}
#titlebar a {
width: 18px;
height: 19px;
line-height: 20px;
overflow: hidden;
display: inline-block;
opacity: .5;
padding: 4px;
border-radius: 4px;
}
#titlebar a::before {
visibility: visible;
}
#titlebar a:hover {
opacity: .8;
border: 1px rgba(0,0,0,.2) solid;
padding: 3px;
}
#titlebar a:active {
opacity: 1;
color: rgba(0,0,0,.6);
/* margin: 1px -1px -1px 1px; */
-moz-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
-webkit-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
-ms-box-shadow: inset 0 0 6px rgba(155,155,155,.8);
box-shadow: inset 0 0 6px rgba(155,155,155,.8);
}
#book-title {
font-weight: 600;
}
#title-seperator {
display: none;
}
#viewer {
width: 80%;
height: 80%;
/* margin-left: 10%; */
margin: 0 auto;
max-width: 1250px;
z-index: 2;
position: relative;
overflow: hidden;
}
#viewer iframe {
border: none;
}
#prev {
left: 40px;
}
#next {
right: 40px;
}
.arrow {
position: absolute;
top: 50%;
margin-top: -32px;
font-size: 64px;
color: #E2E2E2;
font-family: arial, sans-serif;
font-weight: bold;
cursor: pointer;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.arrow:hover {
color: #777;
}
.arrow:active,
.arrow.active {
color: #000;
}
#sidebar {
background: #6b6b6b;
position: absolute;
/* left: -260px; */
/* -webkit-transform: translate(-260px, 0);
-moz-transform: translate(-260px, 0); */
top: 0;
min-width: 300px;
width: 25%;
height: 100%;
-webkit-transition: -webkit-transform .5s;
-moz-transition: -moz-transform .5s;
-ms-transition: -moz-transform .5s;
overflow: hidden;
}
#sidebar.open {
/* left: 0; */
/* -webkit-transform: translate(0, 0);
-moz-transform: translate(0, 0); */
}
#main.closed {
/* left: 300px; */
-webkit-transform: translate(300px, 0);
-moz-transform: translate(300px, 0);
-ms-transform: translate(300px, 0);
}
#main.single {
width: 75%;
}
#main.single #viewer {
/* width: 60%;
margin-left: 20%; */
}
#panels {
background: #4e4e4e;
position: absolute;
left: 0;
top: 0;
width: 100%;
padding: 13px 0;
height: 14px;
-moz-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
-webkit-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
-ms-box-shadow: 0px 1px 3px rgba(0,0,0,.6);
box-shadow: 0px 1px 3px rgba(0,0,0,.6);
}
#opener {
/* padding: 10px 10px; */
float: left;
}
/* #opener #slider {
width: 25px;
} */
#metainfo {
display: inline-block;
text-align: center;
max-width: 80%;
}
#title-controls {
float: right;
}
#panels a {
visibility: hidden;
width: 18px;
height: 20px;
overflow: hidden;
display: inline-block;
color: #ccc;
margin-left: 6px;
}
#panels a::before {
visibility: visible;
}
#panels a:hover {
color: #AAA;
}
#panels a:active {
color: #AAA;
margin: 1px 0 -1px 6px;
}
#panels a.active,
#panels a.active:hover {
color: #AAA;
}
#searchBox {
width: 165px;
float: left;
margin-left: 10px;
margin-top: -1px;
/*
border-radius: 5px;
background: #9b9b9b;
float: left;
margin-left: 5px;
margin-top: -5px;
padding: 3px 10px;
color: #000;
border: none;
outline: none; */
}
input::-webkit-input-placeholder {
color: #454545;
}
input:-moz-placeholder {
color: #454545;
}
input:-ms-placeholder {
color: #454545;
}
#divider {
position: absolute;
width: 1px;
border-right: 1px #000 solid;
height: 80%;
z-index: 1;
left: 50%;
margin-left: -1px;
top: 10%;
opacity: .15;
box-shadow: -2px 0 15px rgba(0, 0, 0, 1);
display: none;
}
#divider.show {
display: block;
}
#loader {
position: absolute;
z-index: 10;
left: 50%;
top: 50%;
margin: -33px 0 0 -33px;
}
#tocView,
#bookmarksView {
overflow-x: hidden;
overflow-y: hidden;
min-width: 300px;
width: 25%;
height: 100%;
visibility: hidden;
-webkit-transition: visibility 0 ease .5s;
-moz-transition: visibility 0 ease .5s;
-ms-transition: visibility 0 ease .5s;
}
#sidebar.open #tocView,
#sidebar.open #bookmarksView {
overflow-y: auto;
visibility: visible;
-webkit-transition: visibility 0 ease 0;
-moz-transition: visibility 0 ease 0;
-ms-transition: visibility 0 ease 0;
}
#sidebar.open #tocView {
display: block;
}
#tocView > ul,
#bookmarksView > ul {
margin-top: 15px;
margin-bottom: 50px;
padding-left: 20px;
display: block;
}
#tocView li,
#bookmarksView li {
margin-bottom:10px;
width: 225px;
font-family: Georgia, "Times New Roman", Times, serif;
list-style: none;
text-transform: capitalize;
}
#tocView li:active,
#tocView li.currentChapter
{
list-style: none;
}
.list_item a {
color: #AAA;
text-decoration: none;
}
.list_item a.chapter {
font-size: 1em;
}
.list_item a.section {
font-size: .8em;
}
.list_item.currentChapter > a,
.list_item a:hover {
color: #f1f1f1
}
/* #tocView li.openChapter > a, */
.list_item a:hover {
color: #E2E2E2;
}
.list_item ul {
padding-left:10px;
margin-top: 8px;
display: none;
}
.list_item.currentChapter > ul,
.list_item.openChapter > ul {
display: block;
}
#tocView.hidden {
display: none;
}
.toc_toggle {
display: inline-block;
width: 14px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.toc_toggle:before {
content: '▸';
color: #fff;
margin-right: -4px;
}
.currentChapter > .toc_toggle:before,
.openChapter > .toc_toggle:before {
content: '▾';
}
.view {
width: 300px;
height: 100%;
display: none;
padding-top: 50px;
overflow-y: auto;
}
#searchResults {
margin-bottom: 50px;
padding-left: 20px;
display: block;
}
#searchResults li {
margin-bottom:10px;
width: 225px;
font-family: Georgia, "Times New Roman", Times, serif;
list-style: none;
}
#searchResults a {
color: #AAA;
text-decoration: none;
}
#searchResults p {
text-decoration: none;
font-size: 12px;
line-height: 16px;
}
#searchResults p .match {
background: #ccc;
color: #000;
}
#searchResults li > p {
color: #AAA;
}
#searchResults li a:hover {
color: #E2E2E2;
}
#searchView.shown {
display: block;
overflow-y: scroll;
}
#notes {
padding: 0 0 0 34px;
}
#notes li {
color: #eee;
font-size: 12px;
width: 240px;
border-top: 1px #fff solid;
padding-top: 6px;
margin-bottom: 6px;
}
#notes li a {
color: #fff;
display: inline-block;
margin-left: 6px;
}
#notes li a:hover {
text-decoration: underline;
}
#notes li img {
max-width: 240px;
}
#note-text {
display: block;
width: 260px;
height: 80px;
margin: 0 auto;
padding: 5px;
border-radius: 5px;
}
#note-text[disabled], #note-text[disabled="disabled"]{
opacity: .5;
}
#note-anchor {
margin-left: 218px;
margin-top: 5px;
}
#settingsPanel {
display:none;
}
#settingsPanel h3 {
color:#f1f1f1;
font-family:Georgia, "Times New Roman", Times, serif;
margin-bottom:10px;
}
#settingsPanel ul {
margin-top:60px;
list-style-type:none;
}
#settingsPanel li {
font-size:1em;
color:#f1f1f1;
}
#settingsPanel .xsmall { font-size:x-small; }
#settingsPanel .small { font-size:small; }
#settingsPanel .medium { font-size:medium; }
#settingsPanel .large { font-size:large; }
#settingsPanel .xlarge { font-size:x-large; }
.highlight { background-color: yellow }
.modal {
position: fixed;
top: 50%;
left: 50%;
width: 50%;
width: 630px;
height: auto;
z-index: 2000;
visibility: hidden;
margin-left: -320px;
margin-top: -160px;
}
.overlay {
position: fixed;
width: 100%;
height: 100%;
visibility: hidden;
top: 0;
left: 0;
z-index: 1000;
opacity: 0;
background: rgba(255,255,255,0.8);
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-ms-transition: all 0.3s;
transition: all 0.3s;
}
.md-show {
visibility: visible;
}
.md-show ~ .overlay {
opacity: 1;
visibility: visible;
}
/* Content styles */
.md-content {
color: #fff;
background: #6b6b6b;
position: relative;
border-radius: 3px;
margin: 0 auto;
height: 320px;
}
.md-content h3 {
margin: 0;
padding: 6px;
text-align: center;
font-size: 22px;
font-weight: 300;
opacity: 0.8;
background: rgba(0,0,0,0.1);
border-radius: 3px 3px 0 0;
}
.md-content > div {
padding: 15px 40px 30px;
margin: 0;
font-weight: 300;
font-size: 14px;
}
.md-content > div p {
margin: 0;
padding: 10px 0;
}
.md-content > div ul {
margin: 0;
padding: 0 0 30px 20px;
}
.md-content > div ul li {
padding: 5px 0;
}
.md-content button {
display: block;
margin: 0 auto;
font-size: 0.8em;
}
/* Effect 1: Fade in and scale up */
.md-effect-1 .md-content {
-webkit-transform: scale(0.7);
-moz-transform: scale(0.7);
-ms-transform: scale(0.7);
transform: scale(0.7);
opacity: 0;
-webkit-transition: all 0.3s;
-moz-transition: all 0.3s;
-ms-transition: all 0.3s;
transition: all 0.3s;
}
.md-show.md-effect-1 .md-content {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
opacity: 1;
}
.md-content > .closer {
font-size: 18px;
position: absolute;
right: 0;
top: 0;
font-size: 24px;
padding: 4px;
}
@media only screen and (max-width: 1040px) {
#viewer{
width: 50%;
margin-left: 25%;
}
#divider,
#divider.show {
display: none;
}
}
@media only screen and (max-width: 900px) {
#viewer{
width: 60%;
margin-left: 20%;
}
#prev {
left: 20px;
}
#next {
right: 20px;
}
}
@media only screen and (max-width: 550px) {
#viewer{
width: 80%;
margin-left: 10%;
}
#prev {
left: 0;
}
#next {
right: 0;
}
.arrow {
height: 100%;
top: 45px;
width: 10%;
text-indent: -10000px;
}
#main {
-webkit-transform: translate(0, 0);
-moz-transform: translate(0, 0);
-ms-transform: translate(0, 0);
-webkit-transition: -webkit-transform .3s;
-moz-transition: -moz-transform .3s;
-ms-transition: -moz-transform .3s;
}
#main.closed {
-webkit-transform: translate(260px, 0);
-moz-transform: translate(260px, 0);
-ms-transform: translate(260px, 0);
}
#titlebar {
/* font-size: 16px; */
/* margin: 0 50px 0 50px; */
}
#metainfo {
font-size: 10px;
}
#tocView {
width: 260px;
}
#tocView li {
font-size: 12px;
}
#tocView > ul{
padding-left: 10px;
}
}
/* For iPad portrait layouts only */
@media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: portrait) {
#viewer iframe {
width: 460px;
height: 740px;
}
}
/*For iPad landscape layouts only */
@media only screen and (min-device-width: 481px) and (max-device-width: 1024px) and (orientation: landscape) {
#viewer iframe {
width: 460px;
height: 415px;
}
}
/* For iPhone portrait layouts only */
@media only screen and (max-device-width: 480px) and (orientation: portrait) {
#viewer {
width: 256px;
height: 432px;
}
#viewer iframe {
width: 256px;
height: 432px;
}
}
/* For iPhone landscape layouts only */
@media only screen and (max-device-width: 480px) and (orientation: landscape) {
#viewer iframe {
width: 256px;
height: 124px;
}
}
[class^="icon-"]:before, [class*=" icon-"]:before {
font-family: "fontello";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* you can be more comfortable with increased icons size */
font-size: 112%;
}
.icon-search:before { content: '\e807'; } /* '' */
.icon-resize-full-1:before { content: '\e804'; } /* '' */
.icon-cancel-circled2:before { content: '\e80f'; } /* '' */
.icon-link:before { content: '\e80d'; } /* '' */
.icon-bookmark:before { content: '\e805'; } /* '' */
.icon-bookmark-empty:before { content: '\e806'; } /* '' */
.icon-download-cloud:before { content: '\e811'; } /* '' */
.icon-edit:before { content: '\e814'; } /* '' */
.icon-menu:before { content: '\e802'; } /* '' */
.icon-cog:before { content: '\e813'; } /* '' */
.icon-resize-full:before { content: '\e812'; } /* '' */
.icon-cancel-circled:before { content: '\e80e'; } /* '' */
.icon-up-dir:before { content: '\e80c'; } /* '' */
.icon-right-dir:before { content: '\e80b'; } /* '' */
.icon-angle-right:before { content: '\e809'; } /* '' */
.icon-angle-down:before { content: '\e80a'; } /* '' */
.icon-right:before { content: '\e815'; } /* '' */
.icon-list-1:before { content: '\e803'; } /* '' */
.icon-list-numbered:before { content: '\e801'; } /* '' */
.icon-columns:before { content: '\e810'; } /* '' */
.icon-list:before { content: '\e800'; } /* '' */
.icon-resize-small:before { content: '\e808'; } /* '' */

505
static/css/reader/normalize.css vendored Executable file
View File

@ -0,0 +1,505 @@
/*! normalize.css v1.0.1 | MIT License | git.io/normalize */
/* ==========================================================================
HTML5 display definitions
========================================================================== */
/*
* Corrects `block` display not defined in IE 6/7/8/9 and Firefox 3.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section,
summary {
display: block;
}
/*
* Corrects `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
*/
audio,
canvas,
video {
display: inline-block;
*display: inline;
*zoom: 1;
}
/*
* Prevents modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/*
* Addresses styling for `hidden` attribute not present in IE 7/8/9, Firefox 3,
* and Safari 4.
* Known issue: no IE 6 support.
*/
[hidden] {
display: none;
}
/* ==========================================================================
Base
========================================================================== */
/*
* 1. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using
* `em` units.
* 2. Prevents iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-size: 100%; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
-ms-text-size-adjust: 100%; /* 2 */
}
/*
* Addresses `font-family` inconsistency between `textarea` and other form
* elements.
*/
html,
button,
input,
select,
textarea {
font-family: sans-serif;
}
/*
* Addresses margins handled incorrectly in IE 6/7.
*/
body {
margin: 0;
}
/* ==========================================================================
Links
========================================================================== */
/*
* Addresses `outline` inconsistency between Chrome and other browsers.
*/
a:focus {
outline: thin dotted;
}
/*
* Improves readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* ==========================================================================
Typography
========================================================================== */
/*
* Addresses font sizes and margins set differently in IE 6/7.
* Addresses font sizes within `section` and `article` in Firefox 4+, Safari 5,
* and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
h2 {
font-size: 1.5em;
margin: 0.83em 0;
}
h3 {
font-size: 1.17em;
margin: 1em 0;
}
h4 {
font-size: 1em;
margin: 1.33em 0;
}
h5 {
font-size: 0.83em;
margin: 1.67em 0;
}
h6 {
font-size: 0.75em;
margin: 2.33em 0;
}
/*
* Addresses styling not present in IE 7/8/9, Safari 5, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/*
* Addresses style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome.
*/
b,
strong {
font-weight: bold;
}
blockquote {
margin: 1em 40px;
}
/*
* Addresses styling not present in Safari 5 and Chrome.
*/
dfn {
font-style: italic;
}
/*
* Addresses styling not present in IE 6/7/8/9.
*/
mark {
background: #ff0;
color: #000;
}
/*
* Addresses margins set differently in IE 6/7.
*/
p,
pre {
margin: 1em 0;
}
/*
* Corrects font family set oddly in IE 6, Safari 4/5, and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, serif;
_font-family: 'courier new', monospace;
font-size: 1em;
}
/*
* Improves readability of pre-formatted text in all browsers.
*/
pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
}
/*
* Addresses CSS quotes not supported in IE 6/7.
*/
q {
quotes: none;
}
/*
* Addresses `quotes` property not supported in Safari 4.
*/
q:before,
q:after {
content: '';
content: none;
}
/*
* Addresses inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/*
* Prevents `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* ==========================================================================
Lists
========================================================================== */
/*
* Addresses margins set differently in IE 6/7.
*/
dl,
menu,
ol,
ul {
margin: 1em 0;
}
dd {
margin: 0 0 0 40px;
}
/*
* Addresses paddings set differently in IE 6/7.
*/
menu,
ol,
ul {
padding: 0 0 0 40px;
}
/*
* Corrects list images handled incorrectly in IE 7.
*/
nav ul,
nav ol {
list-style: none;
list-style-image: none;
}
/* ==========================================================================
Embedded content
========================================================================== */
/*
* 1. Removes border when inside `a` element in IE 6/7/8/9 and Firefox 3.
* 2. Improves image quality when scaled in IE 7.
*/
img {
border: 0; /* 1 */
-ms-interpolation-mode: bicubic; /* 2 */
}
/*
* Corrects overflow displayed oddly in IE 9.
*/
svg:not(:root) {
overflow: hidden;
}
/* ==========================================================================
Figures
========================================================================== */
/*
* Addresses margin not present in IE 6/7/8/9, Safari 5, and Opera 11.
*/
figure {
margin: 0;
}
/* ==========================================================================
Forms
========================================================================== */
/*
* Corrects margin displayed oddly in IE 6/7.
*/
form {
margin: 0;
}
/*
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/*
* 1. Corrects color not being inherited in IE 6/7/8/9.
* 2. Corrects text not wrapping in Firefox 3.
* 3. Corrects alignment displayed oddly in IE 6/7.
*/
legend {
border: 0; /* 1 */
padding: 0;
white-space: normal; /* 2 */
*margin-left: -7px; /* 3 */
}
/*
* 1. Corrects font size not being inherited in all browsers.
* 2. Addresses margins set differently in IE 6/7, Firefox 3+, Safari 5,
* and Chrome.
* 3. Improves appearance and consistency in all browsers.
*/
button,
input,
select,
textarea {
font-size: 100%; /* 1 */
margin: 0; /* 2 */
vertical-align: baseline; /* 3 */
*vertical-align: middle; /* 3 */
}
/*
* Addresses Firefox 3+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
button,
input {
line-height: normal;
}
/*
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Corrects inability to style clickable `input` types in iOS.
* 3. Improves usability and consistency of cursor style between image-type
* `input` and others.
* 4. Removes inner spacing in IE 7 without affecting normal text inputs.
* Known issue: inner spacing remains in IE 6.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
*overflow: visible; /* 4 */
}
/*
* Re-set default cursor for disabled elements.
*/
button[disabled],
input[disabled] {
cursor: default;
}
/*
* 1. Addresses box sizing set to content-box in IE 8/9.
* 2. Removes excess padding in IE 8/9.
* 3. Removes excess padding in IE 7.
* Known issue: excess padding remains in IE 6.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
*height: 13px; /* 3 */
*width: 13px; /* 3 */
}
/*
* 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome.
* 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome
* (include `-moz` to future-proof).
*/
/*
input[type="search"] {
-webkit-appearance: textfield;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
box-sizing: content-box;
}
*/
/*
* Removes inner padding and search cancel button in Safari 5 and Chrome
* on OS X.
*/
/* input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
} */
/*
* Removes inner padding and border in Firefox 3+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/*
* 1. Removes default vertical scrollbar in IE 6/7/8/9.
* 2. Improves readability and alignment in all browsers.
*/
textarea {
overflow: auto; /* 1 */
vertical-align: top; /* 2 */
}
/* ==========================================================================
Tables
========================================================================== */
/*
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,96 @@
/* http://davidwalsh.name/css-tooltips */
/* base CSS element */
.popup {
background: #eee;
border: 1px solid #ccc;
padding: 10px;
border-radius: 8px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
position: fixed;
max-width: 300px;
font-size: 12px;
display: none;
margin-left: 2px;
margin-top: 30px;
}
.popup.above {
margin-top: -10px;
}
.popup.left {
margin-left: -20px;
}
.popup.right {
margin-left: 40px;
}
.pop_content {
max-height: 225px;
overflow-y: auto;
}
.pop_content > p {
margin-top: 0;
}
/* below */
.popup:before {
position: absolute;
display: inline-block;
border-bottom: 10px solid #eee;
border-right: 10px solid transparent;
border-left: 10px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
left: 50%;
top: -10px;
margin-left: -6px;
content: '';
}
.popup:after {
position: absolute;
display: inline-block;
border-bottom: 9px solid #eee;
border-right: 9px solid transparent;
border-left: 9px solid transparent;
left: 50%;
top: -9px;
margin-left: -5px;
content: '';
}
/* above */
.popup.above:before {
border-bottom: none;
border-top: 10px solid #eee;
border-top-color: rgba(0, 0, 0, 0.2);
top: 100%;
}
.popup.above:after {
border-bottom: none;
border-top: 9px solid #eee;
top: 100%;
}
.popup.left:before,
.popup.left:after
{
left: 20px;
}
.popup.right:before,
.popup.right:after
{
left: auto;
right: 20px;
}
.popup.show, .popup.on {
display: block;
}

BIN
static/fonts/fontello.eot Normal file

Binary file not shown.

33
static/fonts/fontello.svg Normal file
View File

@ -0,0 +1,33 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2013 by original authors @ fontello.com</metadata>
<defs>
<font id="fontello" horiz-adv-x="1000" >
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="search" unicode="&#xe807;" d="m643 386q0 103-74 176t-176 74t-177-74t-73-176t73-177t177-73t176 73t74 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69q-80 0-153 31t-125 84t-84 125t-31 153t31 152t84 126t125 84t153 31t152-31t126-84t84-126t31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
<glyph glyph-name="resize-full-1" unicode="&#xe804;" d="m784 111l127 128l0-336l-335 0l128 130l-128 127l79 79z m-431 686l-129-127l128-127l-80-80l-126 128l-128-129l0 335l335 0z m0-637l-129-127l129-130l-335 0l0 336l128-128l128 128z m558 637l0-335l-127 129l-128-128l-79 80l127 127l-128 127l335 0z" horiz-adv-x="928" />
<glyph glyph-name="cancel-circled2" unicode="&#xe80f;" d="m612 248l-81-82q-6-5-13-5t-13 5l-76 77l-77-77q-5-5-13-5t-13 5l-81 82q-6 5-6 13t6 13l76 76l-76 76q-6 6-6 13t6 13l81 82q6 5 13 5t13-5l77-77l76 77q6 5 13 5t13-5l81-82q6-5 6-13t-6-13l-76-76l76-76q6-6 6-13t-6-13z m120 102q0 83-41 152t-110 111t-152 41t-153-41t-110-111t-41-152t41-152t110-111t153-41t152 41t110 111t41 152z m125 0q0-117-57-215t-156-156t-215-58t-216 58t-155 156t-58 215t58 215t155 156t216 58t215-58t156-156t57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="link" unicode="&#xe80d;" d="m812 171q0 23-15 38l-116 116q-16 16-38 16q-24 0-40-18q1-1 10-10t12-12t9-11t7-14t2-15q0-23-16-38t-38-16q-8 0-15 2t-14 7t-11 9t-12 12t-10 10q-19-17-19-40q0-23 16-38l115-116q15-15 38-15q22 0 38 15l82 81q15 16 15 37z m-392 394q0 22-15 38l-115 115q-16 16-38 16q-22 0-38-15l-82-82q-16-15-16-37q0-22 16-38l116-116q15-15 38-15q23 0 40 17q-2 2-11 11t-12 12t-8 10t-7 14t-2 16q0 22 15 38t38 15q9 0 16-2t14-7t10-8t12-12t11-11q18 17 18 41z m500-394q0-67-48-113l-82-81q-46-47-113-47q-68 0-114 48l-115 115q-46 47-46 114q0 68 49 116l-49 49q-48-49-116-49q-67 0-114 47l-116 116q-47 47-47 114t47 113l82 82q47 46 114 46q67 0 114-47l114-116q47-46 47-113q0-69-49-117l49-49q48 49 116 49q67 0 114-47l116-116q47-47 47-114z" horiz-adv-x="928.6" />
<glyph glyph-name="bookmark" unicode="&#xe805;" d="m650 779q12 0 24-5q19-8 29-23t11-35v-719q0-19-11-35t-29-23q-10-4-24-4q-27 0-47 18l-246 236l-246-236q-20-19-46-19q-13 0-25 5q-18 7-29 23t-11 35v719q0 19 11 35t29 23q12 5 25 5h585z" horiz-adv-x="714.3" />
<glyph glyph-name="bookmark-empty" unicode="&#xe806;" d="m643 707h-572v-693l237 227l49 47l50-47l236-227v693z m7 72q12 0 24-5q19-8 29-23t11-35v-719q0-19-11-35t-29-23q-10-4-24-4q-27 0-47 18l-246 236l-246-236q-20-19-46-19q-13 0-25 5q-18 7-29 23t-11 35v719q0 19 11 35t29 23q12 5 25 5h585z" horiz-adv-x="714.3" />
<glyph glyph-name="download-cloud" unicode="&#xe811;" d="m714 332q0 8-5 13t-13 5h-125v196q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-196h-125q-8 0-13-5t-5-13q0-8 5-13l196-196q5-5 13-5t13 5l196 196q5 6 5 13z m357-125q0-89-62-151t-152-63h-607q-103 0-177 73t-73 177q0 72 39 134t105 92q-1 17-1 24q0 118 84 202t202 84q87 0 159-49t105-129q40 35 93 35q59 0 101-42t42-101q0-43-23-77q72-17 119-76t46-133z" horiz-adv-x="1071.4" />
<glyph glyph-name="edit" unicode="&#xe814;" d="m496 189l64 65l-85 85l-64-65v-31h53v-54h32z m245 402q-9 9-18 0l-196-196q-9-9 0-18t18 0l196 196q9 9 0 18z m45-331v-106q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q35 0 65-14q9-4 10-13q2-10-5-16l-27-28q-8-8-18-4q-13 3-25 3h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v70q0 7 5 12l36 36q8 8 20 4t11-16z m-54 411l161-160l-375-375h-161v160z m248-73l-51-52l-161 161l51 51q16 16 38 16t38-16l85-84q16-16 16-38t-16-38z" horiz-adv-x="1000" />
<glyph glyph-name="menu" unicode="&#xe802;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
<glyph glyph-name="cog" unicode="&#xe813;" d="m571 350q0 59-41 101t-101 42t-101-42t-42-101t42-101t101-42t101 42t41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51q19-27 59-77q6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21q-9-76-16-104q-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5q-8 0-14 6q-70 64-92 94q-4 5-4 13q0 6 5 12q8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51q-23 32-60 77q-6 7-6 14q0 5 5 12q15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21q9 76 17 104q3 15 20 15h124q7 0 13-4t7-12l15-103q28-9 50-21l80 60q5 5 13 5q7 0 14-5q72-67 92-95q4-5 4-13q0-6-4-12q-9-12-29-38t-30-39q14-28 23-55l102-15q7-1 12-7t4-13z" horiz-adv-x="857.1" />
<glyph glyph-name="resize-full" unicode="&#xe812;" d="m421 261q0-8-5-13l-185-185l80-81q10-10 10-25t-10-25t-25-11h-250q-15 0-25 11t-11 25v250q0 15 11 25t25 11t25-11l80-80l185 185q6 6 13 6t13-6l64-63q5-6 5-13z m436 482v-250q0-15-10-25t-26-11t-25 11l-80 80l-185-185q-6-6-13-6t-13 6l-64 63q-5 6-5 13t5 13l186 185l-81 81q-10 10-10 25t10 25t25 11h250q15 0 26-11t10-25z" horiz-adv-x="857.1" />
<glyph glyph-name="cancel-circled" unicode="&#xe80e;" d="m641 224q0 14-10 25l-101 101l101 101q10 11 10 25q0 15-10 26l-51 50q-10 11-25 11q-15 0-25-11l-101-101l-101 101q-11 11-26 11q-15 0-25-11l-50-50q-11-11-11-26q0-14 11-25l101-101l-101-101q-11-11-11-25q0-15 11-26l50-50q10-11 25-11q15 0 26 11l101 101l101-101q10-11 25-11q15 0 25 11l51 50q10 11 10 26z m216 126q0-117-57-215t-156-156t-215-58t-216 58t-155 156t-58 215t58 215t155 156t216 58t215-58t156-156t57-215z" horiz-adv-x="857.1" />
<glyph glyph-name="up-dir" unicode="&#xe80c;" d="m571 171q0-14-10-25t-25-10h-500q-15 0-25 10t-11 25t11 26l250 250q10 10 25 10t25-10l250-250q10-11 10-26z" horiz-adv-x="571.4" />
<glyph glyph-name="right-dir" unicode="&#xe80b;" d="m321 350q0-14-10-25l-250-250q-11-11-25-11t-25 11t-11 25v500q0 15 11 25t25 11t25-11l250-250q10-10 10-25z" horiz-adv-x="357.1" />
<glyph glyph-name="angle-right" unicode="&#xe809;" d="m332 314q0-7-6-13l-260-260q-5-5-12-5t-13 5l-28 28q-6 6-6 13t6 13l219 219l-219 220q-6 5-6 12t6 13l28 28q5 6 13 6t12-6l260-260q6-5 6-13z" horiz-adv-x="357.1" />
<glyph glyph-name="angle-down" unicode="&#xe80a;" d="m600 439q0-7-6-13l-260-260q-5-5-13-5t-12 5l-260 260q-6 6-6 13t6 13l27 28q6 6 13 6t13-6l219-219l220 219q5 6 13 6t12-6l28-28q6-5 6-13z" horiz-adv-x="642.9" />
<glyph glyph-name="right" unicode="&#xe815;" d="m1000 404v-108q0-7-5-12t-13-5h-696v-125q0-12-11-17t-19 3l-215 196q-5 5-5 12q0 8 5 14l215 197q9 8 19 4q11-5 11-17v-125h696q8 0 13-5t5-12z" horiz-adv-x="1000" />
<glyph glyph-name="list-1" unicode="&#xe803;" d="m143 118v-107q0-7-5-13t-13-5h-107q-7 0-13 5t-5 13v107q0 7 5 12t13 6h107q7 0 13-6t5-12z m0 214v-107q0-7-5-13t-13-5h-107q-7 0-13 5t-5 13v107q0 7 5 13t13 5h107q7 0 13-5t5-13z m0 214v-107q0-7-5-12t-13-6h-107q-7 0-13 6t-5 12v107q0 8 5 13t13 5h107q7 0 13-5t5-13z m857-428v-107q0-7-5-13t-13-5h-750q-7 0-12 5t-6 13v107q0 7 6 12t12 6h750q7 0 13-6t5-12z m-857 643v-107q0-8-5-13t-13-5h-107q-7 0-13 5t-5 13v107q0 7 5 12t13 6h107q7 0 13-6t5-12z m857-429v-107q0-7-5-13t-13-5h-750q-7 0-12 5t-6 13v107q0 7 6 13t12 5h750q7 0 13-5t5-13z m0 214v-107q0-7-5-12t-13-6h-750q-7 0-12 6t-6 12v107q0 8 6 13t12 5h750q7 0 13-5t5-13z m0 215v-107q0-8-5-13t-13-5h-750q-7 0-12 5t-6 13v107q0 7 6 12t12 6h750q7 0 13-6t5-12z" horiz-adv-x="1000" />
<glyph glyph-name="list-numbered" unicode="&#xe801;" d="m213-54q0-45-31-70t-75-26q-60 0-96 37l31 49q28-25 60-25q16 0 28 8t12 24q0 35-59 31l-14 31q4 6 18 24t24 31t20 21v1q-9 0-27-1t-27 0v-30h-59v85h186v-49l-53-65q28-6 45-27t17-49z m1 350v-89h-202q-4 20-4 30q0 29 14 52t31 38t37 27t31 24t14 25q0 14-9 22t-22 7q-25 0-45-32l-47 33q13 28 40 44t59 16q40 0 68-23t28-63q0-28-19-51t-42-36t-42-28t-20-30h71v34h59z m786-178v-107q0-8-5-13t-13-5h-678q-8 0-13 5t-5 13v107q0 8 5 13t13 5h678q7 0 13-6t5-12z m-786 502v-56h-187v56h60q0 22 0 68t1 67v7h-1q-5-10-28-30l-40 42l76 71h59v-225h60z m786-216v-108q0-7-5-12t-13-5h-678q-8 0-13 5t-5 12v108q0 7 5 12t13 5h678q7 0 13-5t5-12z m0 285v-107q0-7-5-12t-13-6h-678q-8 0-13 6t-5 12v107q0 8 5 13t13 5h678q7 0 13-5t5-13z" horiz-adv-x="1000" />
<glyph glyph-name="columns" unicode="&#xe810;" d="m89-7h340v643h-358v-625q0-8 6-13t12-5z m768 18v625h-357v-643h339q8 0 13 5t5 13z m72 678v-678q0-37-27-63t-63-27h-750q-36 0-63 27t-26 63v678q0 37 26 63t63 27h750q37 0 63-27t27-63z" horiz-adv-x="928.6" />
<glyph glyph-name="list" unicode="&#xe800;" d="m100 200q20 0 35-15t15-35t-15-35t-35-15l-50 0q-20 0-35 15t-15 35t14 35t36 15l50 0z m0 200q20 0 35-15t15-35t-15-35t-35-15l-50 0q-20 0-35 15t-15 35t14 35t36 15l50 0z m0 200q20 0 35-15t15-35t-15-35t-35-15l-50 0q-20 0-35 15t-15 35t14 35t36 15l50 0z m200-100q-20 0-35 15t-15 35t15 35t35 15l350 0q22 0 36-15t14-35t-15-35t-35-15l-350 0z m350-100q22 0 36-15t14-35t-15-35t-35-15l-350 0q-20 0-35 15t-15 35t15 35t35 15l350 0z m0-200q22 0 36-15t14-35t-15-35t-35-15l-350 0q-20 0-35 15t-15 35t15 35t35 15l350 0z" horiz-adv-x="700" />
<glyph glyph-name="resize-small" unicode="&#xe808;" d="m429 314v-250q0-14-11-25t-25-10t-25 10l-81 81l-185-186q-5-5-13-5t-13 5l-63 64q-6 5-6 13t6 13l185 185l-80 80q-11 11-11 25t11 25t25 11h250q14 0 25-11t11-25z m421 375q0-7-6-13l-185-185l80-80q11-11 11-25t-11-25t-25-11h-250q-14 0-25 11t-10 25v250q0 14 10 25t25 10t25-10l81-81l185 186q6 5 13 5t13-5l63-64q6-5 6-13z" horiz-adv-x="857.1" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
static/fonts/fontello.ttf Normal file

Binary file not shown.

BIN
static/fonts/fontello.woff Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -1,14 +0,0 @@
var $j = jQuery.noConflict();
$j().ready(function(){
var contentblock = $j('#content-block, .user-block-hide');
contentblock.on('mouseenter', '.panelview', function() {
$j(this).children('.panelfront').removeClass('side1').addClass('side2');
$j(this).children('.panelback').removeClass('side2').addClass('side1');
});
contentblock.on('mouseleave', '.panelview', function() {
$j(this).children('.panelback').removeClass('side1').addClass('side2');
$j(this).children('.panelfront').removeClass('side2').addClass('side1');
});
});

5
static/js/jquery-1.12.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

8
static/js/reader/epub.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
static/js/reader/hooks.min.js vendored Normal file
View File

@ -0,0 +1 @@
EPUBJS.Hooks.register("beforeChapterDisplay").endnotes=function(a,b){var c=b.contents.querySelectorAll("a[href]"),d=Array.prototype.slice.call(c),e=EPUBJS.core.folder(location.pathname),f=(EPUBJS.cssPath,{});EPUBJS.core.addCss(EPUBJS.cssPath+"popup.css",!1,b.render.document.head),d.forEach(function(a){function c(){var c,h,n=b.height,o=b.width,p=225;m||(c=j.cloneNode(!0),m=c.querySelector("p")),f[i]||(f[i]=document.createElement("div"),f[i].setAttribute("class","popup"),pop_content=document.createElement("div"),f[i].appendChild(pop_content),pop_content.appendChild(m),pop_content.setAttribute("class","pop_content"),b.render.document.body.appendChild(f[i]),f[i].addEventListener("mouseover",d,!1),f[i].addEventListener("mouseout",e,!1),b.on("renderer:pageChanged",g,this),b.on("renderer:pageChanged",e,this)),c=f[i],h=a.getBoundingClientRect(),k=h.left,l=h.top,c.classList.add("show"),popRect=c.getBoundingClientRect(),c.style.left=k-popRect.width/2+"px",c.style.top=l+"px",p>n/2.5&&(p=n/2.5,pop_content.style.maxHeight=p+"px"),popRect.height+l>=n-25?(c.style.top=l-popRect.height+"px",c.classList.add("above")):c.classList.remove("above"),k-popRect.width<=0?(c.style.left=k+"px",c.classList.add("left")):c.classList.remove("left"),k+popRect.width/2>=o?(c.style.left=k-300+"px",popRect=c.getBoundingClientRect(),c.style.left=k-popRect.width+"px",popRect.height+l>=n-25?(c.style.top=l-popRect.height+"px",c.classList.add("above")):c.classList.remove("above"),c.classList.add("right")):c.classList.remove("right")}function d(){f[i].classList.add("on")}function e(){f[i].classList.remove("on")}function g(){setTimeout(function(){f[i].classList.remove("show")},100)}var h,i,j,k,l,m;"noteref"==a.getAttribute("epub:type")&&(h=a.getAttribute("href"),i=h.replace("#",""),j=b.render.document.getElementById(i),a.addEventListener("mouseover",c,!1),a.addEventListener("mouseout",g,!1))}),a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").mathml=function(a,b){if(b.currentChapter.manifestProperties.indexOf("mathml")!==-1){b.render.iframe.contentWindow.mathmlCallback=a;var c=document.createElement("script");c.type="text/x-mathjax-config",c.innerHTML=' MathJax.Hub.Register.StartupHook("End",function () { window.mathmlCallback(); }); MathJax.Hub.Config({jax: ["input/TeX","input/MathML","output/SVG"],extensions: ["tex2jax.js","mml2jax.js","MathEvents.js"],TeX: {extensions: ["noErrors.js","noUndefined.js","autoload-all.js"]},MathMenu: {showRenderer: false},menuSettings: {zoom: "Click"},messageStyle: "none"}); ',b.doc.body.appendChild(c),EPUBJS.core.addScript("http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",null,b.doc.head)}else a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").smartimages=function(a,b){var c=b.contents.querySelectorAll("img"),d=Array.prototype.slice.call(c),e=b.height;if("reflowable"!=b.layoutSettings.layout)return void a();d.forEach(function(a){var c=function(){var c,d=a.getBoundingClientRect(),f=d.height,g=d.top,h=a.getAttribute("data-height"),i=h||f,j=Number(getComputedStyle(a,"").fontSize.match(/(\d*(\.\d*)?)px/)[1]),k=j?j/2:0;e=b.contents.clientHeight,g<0&&(g=0),a.style.maxWidth="100%",i+g>=e?(g<e/2?(c=e-g-k,a.style.maxHeight=c+"px",a.style.width="auto"):(i>e&&(a.style.maxHeight=e+"px",a.style.width="auto",d=a.getBoundingClientRect(),i=d.height),a.style.display="block",a.style.WebkitColumnBreakBefore="always",a.style.breakBefore="column"),a.setAttribute("data-height",c)):(a.style.removeProperty("max-height"),a.style.removeProperty("margin-top"))},d=function(){b.off("renderer:resized",c),b.off("renderer:chapterUnload",this)};a.addEventListener("load",c,!1),b.on("renderer:resized",c),b.on("renderer:chapterUnload",d),c()}),a&&a()},EPUBJS.Hooks.register("beforeChapterDisplay").transculsions=function(a,b){var c=b.contents.querySelectorAll("[transclusion]");Array.prototype.slice.call(c).forEach(function(a){function c(){j=g,k=h,j>chapter.colWidth&&(d=chapter.colWidth/j,j=chapter.colWidth,k*=d),f.width=j,f.height=k}var d,e=a.getAttribute("ref"),f=document.createElement("iframe"),g=a.getAttribute("width"),h=a.getAttribute("height"),i=a.parentNode,j=g,k=h;c(),b.listenUntil("renderer:resized","renderer:chapterUnloaded",c),f.src=e,i.replaceChild(f,a)}),a&&a()};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,14 @@
EPUBJS.Hooks.register("beforeChapterDisplay").highlight = function(callback, renderer){
// EPUBJS.core.addScript("js/libs/jquery.highlight.js", null, renderer.doc.head);
var s = document.createElement("style");
s.innerHTML =".highlight { background: yellow; font-weight: normal; }";
renderer.render.document.head.appendChild(s);
if(callback) callback();
}

4
static/js/reader/libs/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,145 @@
/*!
* screenfull
* v2.0.0 - 2014-12-22
* (c) Sindre Sorhus; MIT License
*/
(function () {
'use strict';
var isCommonjs = typeof module !== 'undefined' && module.exports;
var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;
var fn = (function () {
var val;
var valLength;
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];
var i = 0;
var l = fnMap.length;
var ret = {};
for (; i < l; i++) {
val = fnMap[i];
if (val && val[1] in document) {
for (i = 0, valLength = val.length; i < valLength; i++) {
ret[fnMap[0][i]] = val[i];
}
return ret;
}
}
return false;
})();
var screenfull = {
request: function (elem) {
var request = fn.requestFullscreen;
elem = elem || document.documentElement;
// Work around Safari 5.1 bug: reports support for
// keyboard in fullscreen even though it doesn't.
// Browser sniffing, since the alternative with
// setTimeout is even worse.
if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
elem[request]();
} else {
elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
}
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
if (this.isFullscreen) {
this.exit();
} else {
this.request(elem);
}
},
raw: fn
};
if (!fn) {
if (isCommonjs) {
module.exports = false;
} else {
window.screenfull = false;
}
return;
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: function () {
return !!document[fn.fullscreenElement];
}
},
element: {
enumerable: true,
get: function () {
return document[fn.fullscreenElement];
}
},
enabled: {
enumerable: true,
get: function () {
// Coerce to boolean in case of old WebKit
return !!document[fn.fullscreenEnabled];
}
}
});
if (isCommonjs) {
module.exports = screenfull;
} else {
window.screenfull = screenfull;
}
})();

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