commit 9000ecdce5d2dfa44af651379c469c0d6bead890 Author: tanshu Date: Sun May 24 14:09:35 2015 +0530 Initial Commit. Gitignore ignores all PyCharm files as well as recommended python files Basic starter project with Pyramid 1.5.x Templates are copied from the OpenPhoto (Trovebox) files Targets: 1. Photo management 2. Angularjs with keyboard/swipe navigation 3. Json API compatible with OpenPhoto 4. Amazon S3 support 5. Tags, etc. 6. The one true source of all a person's photos In Greek mythology, Soter was the spirit of safety, preservation and deliverance from harm. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd64966 --- /dev/null +++ b/.gitignore @@ -0,0 +1,106 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties \ No newline at end of file diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..35a34f3 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,4 @@ +0.0 +--- + +- Initial version diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..e17f830 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include *.txt *.ini *.cfg *.rst +recursive-include soter *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..ffdd9f8 --- /dev/null +++ b/README.txt @@ -0,0 +1 @@ +Soter README diff --git a/development.ini b/development.ini new file mode 100644 index 0000000..fb6a7e0 --- /dev/null +++ b/development.ini @@ -0,0 +1,60 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/environment.html +### + +[app:main] +use = egg:Soter + +pyramid.reload_templates = true +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en +pyramid.includes = + pyramid_debugtoolbar + +# By default, the toolbar only appears for clients from IP addresses +# '127.0.0.1' and '::1'. +# debugtoolbar.hosts = 127.0.0.1 ::1 + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html +### + +[loggers] +keys = root, soter + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = INFO +handlers = console + +[logger_soter] +level = DEBUG +handlers = +qualname = soter + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/production.ini b/production.ini new file mode 100644 index 0000000..c55d340 --- /dev/null +++ b/production.ini @@ -0,0 +1,54 @@ +### +# app configuration +# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/environment.html +### + +[app:main] +use = egg:Soter + +pyramid.reload_templates = false +pyramid.debug_authorization = false +pyramid.debug_notfound = false +pyramid.debug_routematch = false +pyramid.default_locale_name = en + +### +# wsgi server configuration +### + +[server:main] +use = egg:waitress#main +host = 0.0.0.0 +port = 6543 + +### +# logging configuration +# http://docs.pylonsproject.org/projects/pyramid/en/1.5-branch/narr/logging.html +### + +[loggers] +keys = root, soter + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console + +[logger_soter] +level = WARN +handlers = +qualname = soter + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..963c2e6 --- /dev/null +++ b/setup.py @@ -0,0 +1,42 @@ +import os + +from setuptools import setup, find_packages + +here = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(here, 'README.txt')) as f: + README = f.read() +with open(os.path.join(here, 'CHANGES.txt')) as f: + CHANGES = f.read() + +requires = [ + 'pyramid', + 'pyramid_chameleon', + 'pyramid_debugtoolbar', + 'waitress', + ] + +setup(name='Soter', + version='0.0', + description='Soter', + long_description=README + '\n\n' + CHANGES, + classifiers=[ + "Programming Language :: Python", + "Framework :: Pyramid", + "Topic :: Internet :: WWW/HTTP", + "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", + ], + author='', + author_email='', + url='', + keywords='web pyramid pylons', + packages=find_packages(), + include_package_data=True, + zip_safe=False, + install_requires=requires, + tests_require=requires, + test_suite="soter", + entry_points="""\ + [paste.app_factory] + main = soter:main + """, + ) diff --git a/soter/__init__.py b/soter/__init__.py new file mode 100644 index 0000000..7a20df8 --- /dev/null +++ b/soter/__init__.py @@ -0,0 +1,29 @@ +from pyramid.config import Configurator + + +def main(global_config, **settings): + """ This function returns a Pyramid WSGI application. + """ + config = Configurator(settings=settings) + config.include('pyramid_chameleon') + config.add_static_view('static', 'static', cache_max_age=3600) + config.add_route('home', '/') + + + # + # Hello world test endpoint. + # If ?auth=true is passed then it will run OAuth validation on the request. + # + config.add_route('hello', '/v{version}/hello.json') + + # + # Action endpoints + # All action endpoints follow the same convention. + # Everything in []'s are optional + # /action/{id}[/{additional}].json + config.add_route('view', '/v{version}/action/{id}/view.json') + config.add_route('delete', '/v{version}/action/{id}/delete.json') + config.add_route('create', '/v{version}/action/{id}/create.json') + + config.scan() + return config.make_wsgi_app() diff --git a/soter/static/pyramid-16x16.png b/soter/static/pyramid-16x16.png new file mode 100644 index 0000000..9792031 Binary files /dev/null and b/soter/static/pyramid-16x16.png differ diff --git a/soter/static/pyramid.png b/soter/static/pyramid.png new file mode 100644 index 0000000..4ab837b Binary files /dev/null and b/soter/static/pyramid.png differ diff --git a/soter/static/theme.css b/soter/static/theme.css new file mode 100644 index 0000000..be50ad4 --- /dev/null +++ b/soter/static/theme.css @@ -0,0 +1,152 @@ +@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700); +body { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 300; + color: #ffffff; + background: #bc2131; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 300; +} +p { + font-weight: 300; +} +.font-normal { + font-weight: 400; +} +.font-semi-bold { + font-weight: 600; +} +.font-bold { + font-weight: 700; +} +.starter-template { + margin-top: 250px; +} +.starter-template .content { + margin-left: 10px; +} +.starter-template .content h1 { + margin-top: 10px; + font-size: 60px; +} +.starter-template .content h1 .smaller { + font-size: 40px; + color: #f2b7bd; +} +.starter-template .content .lead { + font-size: 25px; + color: #f2b7bd; +} +.starter-template .content .lead .font-normal { + color: #ffffff; +} +.starter-template .links { + float: right; + right: 0; + margin-top: 125px; +} +.starter-template .links ul { + display: block; + padding: 0; + margin: 0; +} +.starter-template .links ul li { + list-style: none; + display: inline; + margin: 0 10px; +} +.starter-template .links ul li:first-child { + margin-left: 0; +} +.starter-template .links ul li:last-child { + margin-right: 0; +} +.starter-template .links ul li.current-version { + color: #f2b7bd; + font-weight: 400; +} +.starter-template .links ul li a { + color: #ffffff; +} +.starter-template .links ul li a:hover { + text-decoration: underline; +} +.starter-template .links ul li .icon-muted { + color: #eb8b95; + margin-right: 5px; +} +.starter-template .links ul li:hover .icon-muted { + color: #ffffff; +} +.starter-template .copyright { + margin-top: 10px; + font-size: 0.9em; + color: #f2b7bd; + text-transform: lowercase; + float: right; + right: 0; +} +@media (max-width: 1199px) { + .starter-template .content h1 { + font-size: 45px; + } + .starter-template .content h1 .smaller { + font-size: 30px; + } + .starter-template .content .lead { + font-size: 20px; + } +} +@media (max-width: 991px) { + .starter-template { + margin-top: 0; + } + .starter-template .logo { + margin: 40px auto; + } + .starter-template .content { + margin-left: 0; + text-align: center; + } + .starter-template .content h1 { + margin-bottom: 20px; + } + .starter-template .links { + float: none; + text-align: center; + margin-top: 60px; + } + .starter-template .copyright { + float: none; + text-align: center; + } +} +@media (max-width: 767px) { + .starter-template .content h1 .smaller { + font-size: 25px; + display: block; + } + .starter-template .content .lead { + font-size: 16px; + } + .starter-template .links { + margin-top: 40px; + } + .starter-template .links ul li { + display: block; + margin: 0; + } + .starter-template .links ul li .icon-muted { + display: none; + } + .starter-template .copyright { + margin-top: 20px; + } +} diff --git a/soter/static/theme.min.css b/soter/static/theme.min.css new file mode 100644 index 0000000..2f924bc --- /dev/null +++ b/soter/static/theme.min.css @@ -0,0 +1 @@ +@import url(//fonts.googleapis.com/css?family=Open+Sans:300,400,600,700);body{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300;color:#fff;background:#bc2131}h1,h2,h3,h4,h5,h6{font-family:"Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:300}p{font-weight:300}.font-normal{font-weight:400}.font-semi-bold{font-weight:600}.font-bold{font-weight:700}.starter-template{margin-top:250px}.starter-template .content{margin-left:10px}.starter-template .content h1{margin-top:10px;font-size:60px}.starter-template .content h1 .smaller{font-size:40px;color:#f2b7bd}.starter-template .content .lead{font-size:25px;color:#f2b7bd}.starter-template .content .lead .font-normal{color:#fff}.starter-template .links{float:right;right:0;margin-top:125px}.starter-template .links ul{display:block;padding:0;margin:0}.starter-template .links ul li{list-style:none;display:inline;margin:0 10px}.starter-template .links ul li:first-child{margin-left:0}.starter-template .links ul li:last-child{margin-right:0}.starter-template .links ul li.current-version{color:#f2b7bd;font-weight:400}.starter-template .links ul li a{color:#fff}.starter-template .links ul li a:hover{text-decoration:underline}.starter-template .links ul li .icon-muted{color:#eb8b95;margin-right:5px}.starter-template .links ul li:hover .icon-muted{color:#fff}.starter-template .copyright{margin-top:10px;font-size:.9em;color:#f2b7bd;text-transform:lowercase;float:right;right:0}@media (max-width:1199px){.starter-template .content h1{font-size:45px}.starter-template .content h1 .smaller{font-size:30px}.starter-template .content .lead{font-size:20px}}@media (max-width:991px){.starter-template{margin-top:0}.starter-template .logo{margin:40px auto}.starter-template .content{margin-left:0;text-align:center}.starter-template .content h1{margin-bottom:20px}.starter-template .links{float:none;text-align:center;margin-top:60px}.starter-template .copyright{float:none;text-align:center}}@media (max-width:767px){.starter-template .content h1 .smaller{font-size:25px;display:block}.starter-template .content .lead{font-size:16px}.starter-template .links{margin-top:40px}.starter-template .links ul li{display:block;margin:0}.starter-template .links ul li .icon-muted{display:none}.starter-template .copyright{margin-top:20px}} \ No newline at end of file diff --git a/soter/templates/account.html b/soter/templates/account.html new file mode 100644 index 0000000..ff5dcf8 --- /dev/null +++ b/soter/templates/account.html @@ -0,0 +1,33 @@ +
+ + +

Your Account

+ +
+
+

+ Soon your account page will allow you to update your email address, change storage providers and more. + For now, it's just an overview. +

+

Your email address

+
+ +
+
+

Where are your files stored?

+
+ + + Storage provided by openphoto.me + + In your S3 bucket (utility->safe($aws['bucket']); ?>) + + + Your Dropbox account + +
+ You'll be able to change this soon +
+
+
+
\ No newline at end of file diff --git a/soter/templates/manage-albums.html b/soter/templates/manage-albums.html new file mode 100644 index 0000000..f0ae183 --- /dev/null +++ b/soter/templates/manage-albums.html @@ -0,0 +1,56 @@ +
+ +
+

What are albums?

+

+ Albums are a collection of photos. You can use them to share photos from a vacation or a child's birthday party. +
+ They're similar to tags but have a few key differences. +

    +
  1. The permission for who can view a photo applies even when it's in an album. If your photo is private then only you'll be able to see them in your album.
  2. +
  3. You can specify if an album shows up on the Albums page.
  4. +
  5. Albums are fixed unless you explicitly add a photo to it.
  6. +
  7. Add photos to an album using the edit form or on the manage photos page.
  8. +
+

+
+ + + + + +
+

+ Edit utility->safe($album['name']); ?> + + ( + 0) { ?> + utility->safe($album['count']); ?> photos + + No photos in this album + + ) + +

+ + + +
+ +
+ + +
+
+ +
+    Or delete +
+ +
\ No newline at end of file diff --git a/soter/templates/manage-group-form.html b/soter/templates/manage-group-form.html new file mode 100644 index 0000000..2b5191e --- /dev/null +++ b/soter/templates/manage-group-form.html @@ -0,0 +1,12 @@ +
+

Create a new group

+ + + + +    Add + + + +
\ No newline at end of file diff --git a/soter/templates/manage-groups.html b/soter/templates/manage-groups.html new file mode 100644 index 0000000..2b5191e --- /dev/null +++ b/soter/templates/manage-groups.html @@ -0,0 +1,12 @@ +
+

Create a new group

+ + + + +    Add + + + +
\ No newline at end of file diff --git a/soter/templates/manage-password-reset.html b/soter/templates/manage-password-reset.html new file mode 100644 index 0000000..2b6d36d --- /dev/null +++ b/soter/templates/manage-password-reset.html @@ -0,0 +1,18 @@ +
+
+

So you forgot your password, huh?

+

+ No problem. Fill out the form below to reset it. +

+ + + + + + +
+ + + +
+
\ No newline at end of file diff --git a/soter/templates/manage-photos.html b/soter/templates/manage-photos.html new file mode 100644 index 0000000..163aadc --- /dev/null +++ b/soter/templates/manage-photos.html @@ -0,0 +1,33 @@ +
+
+

Tips on updating your photos

+

+ You can easily edit title, tags, permission and licensing of your photos. + When you hover over a photo you'll see two icons. +

    +
  1. The pencil icon brings up a dialog to edit that photo.
  2. +
  3. The checkmark queues that photo in case you wanted to update multiple photos at once.
  4. +
+

+
+ + + +
+ 0) { ?> +
    + +
  • + <?php $this->utility->safe($photo['title']); ?> +
    + + +
    +
  • + +
+
+ + theme->display('partials/no-content.php'); ?> + +
\ No newline at end of file diff --git a/soter/templates/manage-settings.html b/soter/templates/manage-settings.html new file mode 100644 index 0000000..1e36d3b --- /dev/null +++ b/soter/templates/manage-settings.html @@ -0,0 +1,208 @@ +
+
+

Configure your Trovebox site

+
+
+ + +
+
+ Don't want users to download your original photos? No problem. Want to allow the same photo to be uploaded twice? You're at the right spot. +
+
+
+
+
+

General settings

+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
Collaborators
+

+ Enter email addresses for others you'd like to collaborate with you. These users will have full access to your account. They can log in using Mozilla Persona. +

+
+ + value="utility->safe($admins[$i]); ?>" placeholder="user@example.com"> + +
+
+
+
+ +
+ + +
+
+

Your OAuth Applications

+
+
+
+
+ You've granted these applications access to your Trovebox account. Clicking revoke cannot be undone and you may have to reapprove the application. +
+
+
+
+

+ Create a new app +

+ + + + + + + + + + + + + + +
Application Name
+ utility->safe($credential['name']); ?> + + (utility->safe(ucwords($credential['type'])); ?> token created on utility->dateLong($credential['dateCreated']); ?>) + + +
+ View +       + Revoke +
+
+ +
+
+ + +
+
+

Your plugins

+
+
+
+
+ Plugins help you add more features to your Trovebox site. Below is a list of all the available plugins you can activate and configure. +
+
+
+
+ + + + + + + + + + + + + +
Plugin Name
utility->safe($plugin['name']); ?> +
+
Active (Configure or Deactivate)
+
Inactive (Activate)
+
+
+
+
+ + +
+
+

Your sharing tokens

+
+
+
+
+ + + + + + + + + + + + + + + + +
Photos
You don't have any sharing tokens for your photos.
+ Photo utility->safe($photo['data']); ?> + (Sharing token never expiresSharing token expires on utility->dateLong($photo['dateExpires']); ?>) + +
+ View +       + Delete +
+
+ + + + + + + + + + + + + + + + +
Albums
You don't have any sharing tokens for your albums.
+ Album + (Sharing token never expiresSharing token expires on utility->dateLong($album['dateExpires']); ?>) + +
+ View +       + Delete +
+
+
+
\ No newline at end of file diff --git a/soter/templates/mytemplate.pt b/soter/templates/mytemplate.pt new file mode 100644 index 0000000..c835bf1 --- /dev/null +++ b/soter/templates/mytemplate.pt @@ -0,0 +1,66 @@ + + + + + + + + + + + Starter Scaffold for The Pyramid Web Framework + + + + + + + + + + + + + +
+
+
+
+ +
+
+
+

Pyramid Starter scaffold

+

Welcome to ${project}, an application generated by
the Pyramid Web Framework 1.5.7.

+
+
+
+
+ +
+
+ +
+
+
+ + + + + + + + diff --git a/soter/templates/oauth-create.html b/soter/templates/oauth-create.html new file mode 100644 index 0000000..752ac23 --- /dev/null +++ b/soter/templates/oauth-create.html @@ -0,0 +1,37 @@ +
+
+

Create an app

+
+
+
+
+

+

Make sure you trust the site you just came from.

+ If you do not, then simply close this window. + Apps let other programs have access to your Trovebox account. + You'll want to make sure that you trust the site you just came from. +

+
+
+
+
+
+ + + + + +
+ +
+ + +
+
+
\ No newline at end of file diff --git a/soter/templates/photo-edit.html b/soter/templates/photo-edit.html new file mode 100644 index 0000000..a18c4b7 --- /dev/null +++ b/soter/templates/photo-edit.html @@ -0,0 +1,68 @@ +
+ + + + + + + + + + + + + + +
+ +
+ + +
+
+ + 0) { ?> +
+ + +
+ + + 0) { ?> +
+ + +
+ + + +
+ +
+ +
+ +
+
\ No newline at end of file diff --git a/soter/templates/photo-form.html b/soter/templates/photo-form.html new file mode 100644 index 0000000..9e0a7ad --- /dev/null +++ b/soter/templates/photo-form.html @@ -0,0 +1,23 @@ +

Update your plugin: utility->safe($plugin); ?>

+
+
+
+ + $v) { ?> + + + + + + + + + +
+ + +
+
+
+
+ \ No newline at end of file diff --git a/soter/templates/setup-dropbox.html b/soter/templates/setup-dropbox.html new file mode 100644 index 0000000..443d07a --- /dev/null +++ b/soter/templates/setup-dropbox.html @@ -0,0 +1,26 @@ +
+

Connect your Dropbox to Trovebox

+

+ + Click here to create a Dropbox app if you haven't already. + IMPORTANT: make sure you select App Folder access level. +

+
+
+

Enter your Dropbox App credentials

+ + + + + + + + + +
+ Cancel + +
+
+
+
\ No newline at end of file diff --git a/soter/templates/setup.html b/soter/templates/setup.html new file mode 100644 index 0000000..a8ff8b9 --- /dev/null +++ b/soter/templates/setup.html @@ -0,0 +1,135 @@ +
+

Create your Trovebox site (start over)

+ + + +
+ Please fix the following errors +
    + +
  • + +
+
+ +

+ Please fix the following errors + +

+ + + + + +
\ No newline at end of file diff --git a/soter/templates/template.html b/soter/templates/template.html new file mode 100644 index 0000000..93249ad --- /dev/null +++ b/soter/templates/template.html @@ -0,0 +1,30 @@ + + + + + + + <?php getTheme()->meta('titles', $page); ?> + + + + + + + + + + + + + + + +
+

Trovebox

+
+
+ +
+ + \ No newline at end of file diff --git a/soter/templates/upgrade.html b/soter/templates/upgrade.html new file mode 100644 index 0000000..34c3cc1 --- /dev/null +++ b/soter/templates/upgrade.html @@ -0,0 +1,20 @@ +

We need to upgrade from utility->safe($lastVersion); ?> to utility->safe($currentVersion); ?>

+ +

+ Before you start the upgrade you'll want to make sure you have a backup of your database. +

+ + + $readme) { ?> +

Notes for upgrading to utility->safe($version); ?>

+

+ +

+ + + +

+

+ +
+

\ No newline at end of file diff --git a/soter/templates/upload-beta.html b/soter/templates/upload-beta.html new file mode 100644 index 0000000..3bc5041 --- /dev/null +++ b/soter/templates/upload-beta.html @@ -0,0 +1,59 @@ +
+
+
+

Details for your photos

+ + + + + + +
+ + +
+ +
+ +
+ + +
+
+ + + + + + + + +
+ +
+
+ Powered by Dropzone.js +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/soter/templates/upload-confirm.html b/soter/templates/upload-confirm.html new file mode 100644 index 0000000..8951307 --- /dev/null +++ b/soter/templates/upload-confirm.html @@ -0,0 +1,59 @@ + 0) { ?> + +

Your photos are finished uploading! Now what?

+ +

Your photos are finished uploading, but had problems. Now what?

+ + +

+ Post your photos to Facebook or Twitter. +

+

+

+ Or simply go look at your photos. +

+ +

None of your photos were uploaded

+

+ See below for more details. If you continue to have problems drop us a note on our mailing list support@trovebox.com. +

+ + 0) { ?> +

Here's a breakdown of your upload

+ utility->plural(count($successPhotos), 'photo', false), $this->utility->selectPlural(count($successPhotos), 'was', 'were', false)); ?> uploaded successfully. +
+
+
+
+ + 0) { ?> + of them already existed in your account. +
+ +
+
+ + 0) { ?> + utility->plural(count($failure), 'photo', false)); ?> could not be uploaded. Booo! +
+ +
+ \ No newline at end of file diff --git a/soter/templates/upload-token-dialog.html b/soter/templates/upload-token-dialog.html new file mode 100644 index 0000000..577f82e --- /dev/null +++ b/soter/templates/upload-token-dialog.html @@ -0,0 +1,10 @@ +

Enter your name or nickname

+
+
+ +
This helps the account owner know these are your photos
+
+
+ +
+
\ No newline at end of file diff --git a/soter/templates/upload.html b/soter/templates/upload.html new file mode 100644 index 0000000..1e8a2da --- /dev/null +++ b/soter/templates/upload.html @@ -0,0 +1,76 @@ +
+
+
Currently uploading 0 of 0 photos.
+ +
+
+
+
+

Upload from your computer

+
+
+

Unfortunately, it doesn't look like we support your browser. :(

+

+ Try using Firefox. +

+
+
+ +
+ +
+ + Powered by Plupload. +
+
+

Use these settings.

+
+ + + +
+ + +
+ +
+ +
+ + +
+
+ + + + + + + + + + + +
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/soter/tests.py b/soter/tests.py new file mode 100644 index 0000000..896fe85 --- /dev/null +++ b/soter/tests.py @@ -0,0 +1,17 @@ +import unittest + +from pyramid import testing + + +class ViewTests(unittest.TestCase): + def setUp(self): + self.config = testing.setUp() + + def tearDown(self): + testing.tearDown() + + def test_my_view(self): + from .views import my_view + request = testing.DummyRequest() + info = my_view(request) + self.assertEqual(info['project'], 'Soter') diff --git a/soter/views.py b/soter/views.py new file mode 100644 index 0000000..8a44ae5 --- /dev/null +++ b/soter/views.py @@ -0,0 +1,6 @@ +from pyramid.view import view_config + + +@view_config(route_name='home', renderer='templates/mytemplate.pt') +def my_view(request): + return {'project': 'Soter'}