summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoald de Vries <rdevries@thoughtworks.com>2016-12-08 16:59:09 +0100
committerRoald de Vries <rdevries@thoughtworks.com>2016-12-08 16:59:09 +0100
commitfafac3b4128a0993b0de1c6e8ca3062bf1ccc14e (patch)
tree3b9a446e4c82bb8ba94c1cd0adec57c0042dae28
parent521bce7eff5cf921156efe74c91a0499ade43619 (diff)
Revert "[#801] Merge branch 'signup'"
This reverts commit d10f607a4d40587510b0dc31b31fe4750bf4a3a3, reversing changes made to c28abba2f5b1186c671ebef508d40ffaae6d5bc5.
-rw-r--r--.gitignore36
-rw-r--r--README.md2
-rw-r--r--doc/first-steps.md4
-rw-r--r--service/MANIFEST.in2
-rwxr-xr-xservice/go6
-rw-r--r--service/pixelated/adapter/welcome_mail.py2
-rw-r--r--service/pixelated/application.py17
-rw-r--r--service/pixelated/assets/Interstitial.html (renamed from service/templates/Interstitial.html)6
-rw-r--r--service/pixelated/assets/Interstitial.js (renamed from web-ui/public/Interstitial.js)9
-rw-r--r--service/pixelated/assets/__init__.py (renamed from service/templates/__init__.py)0
-rw-r--r--service/pixelated/assets/_login_disclaimer_banner.html (renamed from service/templates/_login_disclaimer_banner.html)0
-rw-r--r--service/pixelated/assets/favicon.png (renamed from web-ui/public/favicon.png)bin592 -> 592 bytes
-rw-r--r--service/pixelated/assets/hive-bg.png (renamed from web-ui/public/hive-bg.png)bin3356 -> 3356 bytes
-rw-r--r--service/pixelated/assets/index.html9
-rw-r--r--service/pixelated/assets/jquery-2.1.3.min.js (renamed from web-ui/public/jquery-2.1.3.min.js)0
-rw-r--r--service/pixelated/assets/login.html (renamed from service/templates/login.html)11
-rw-r--r--service/pixelated/assets/normalize.min.css (renamed from web-ui/public/normalize.min.css)0
-rw-r--r--service/pixelated/assets/opensans.css (renamed from web-ui/public/opensans.css)0
-rw-r--r--service/pixelated/assets/pixelated-logo-orange.svg (renamed from web-ui/public/pixelated-logo-orange.svg)0
-rw-r--r--service/pixelated/assets/pixelated.css (renamed from web-ui/public/pixelated.css)0
-rw-r--r--service/pixelated/assets/snap.svg-min.js (renamed from web-ui/public/snap.svg-min.js)0
-rw-r--r--service/pixelated/assets/welcome.mail.en-US (renamed from service/templates/welcome.mail.en-US)0
-rw-r--r--service/pixelated/assets/welcome.mail.pt-BR (renamed from service/templates/welcome.mail.pt-BR)0
-rw-r--r--service/pixelated/assets/welcome.mail.pt-BR.txt (renamed from service/templates/welcome.mail.pt-BR.txt)0
-rw-r--r--service/pixelated/bitmask_libraries/provider.py2
-rw-r--r--service/pixelated/resources/__init__.py10
-rw-r--r--service/pixelated/resources/auth.py32
-rw-r--r--service/pixelated/resources/inbox_resource.py56
-rw-r--r--service/pixelated/resources/login_resource.py32
-rw-r--r--service/pixelated/resources/root_resource.py120
-rw-r--r--service/pixelated/resources/session.py10
-rw-r--r--service/setup.py4
-rw-r--r--service/test/integration/test_contacts.py1
-rw-r--r--service/test/integration/test_delete_mail.py13
-rw-r--r--service/test/integration/test_drafts.py30
-rw-r--r--service/test/integration/test_feedback_service.py2
-rw-r--r--service/test/integration/test_logout.py6
-rw-r--r--service/test/integration/test_mark_as_read_unread.py29
-rw-r--r--service/test/integration/test_multi_user_login.py8
-rw-r--r--service/test/integration/test_retrieve_attachment.py4
-rw-r--r--service/test/integration/test_static_files.py27
-rw-r--r--service/test/integration/test_tags.py23
-rw-r--r--service/test/integration/test_users_count.py5
-rw-r--r--service/test/support/integration/app_test_client.py67
-rw-r--r--service/test/support/integration/multi_user_client.py29
-rw-r--r--service/test/unit/resources/test_auth.py73
-rw-r--r--service/test/unit/resources/test_inbox_resource.py46
-rw-r--r--service/test/unit/resources/test_login_resource.py15
-rw-r--r--service/test/unit/resources/test_root_resource.py258
-rw-r--r--service/test/unit/resources/test_session.py25
-rw-r--r--service/test/unit/test_welcome_mail.py3
-rw-r--r--web-ui/.bowerrc2
-rw-r--r--web-ui/.jshintignore12
-rw-r--r--web-ui/.jshintrc3
-rw-r--r--web-ui/.tx/config4
-rw-r--r--web-ui/Makefile4
-rw-r--r--web-ui/app/404.html (renamed from web-ui/public/404.html)0
-rw-r--r--web-ui/app/favicon.ico (renamed from web-ui/public/favicon.ico)0
-rw-r--r--web-ui/app/fonts/OpenSans-Bold.woff (renamed from web-ui/public/fonts/OpenSans-Bold.woff)bin14504 -> 14504 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-BoldItalic.woff (renamed from web-ui/public/fonts/OpenSans-BoldItalic.woff)bin15488 -> 15488 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-Extrabold.woff (renamed from web-ui/public/fonts/OpenSans-Extrabold.woff)bin15312 -> 15312 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-ExtraboldItalic.woff (renamed from web-ui/public/fonts/OpenSans-ExtraboldItalic.woff)bin15932 -> 15932 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-Italic.woff (renamed from web-ui/public/fonts/OpenSans-Italic.woff)bin15768 -> 15768 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-Light.woff (renamed from web-ui/public/fonts/OpenSans-Light.woff)bin15048 -> 15048 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-Semibold.woff (renamed from web-ui/public/fonts/OpenSans-Semibold.woff)bin15236 -> 15236 bytes
-rw-r--r--web-ui/app/fonts/OpenSans-SemiboldItalic.woff (renamed from web-ui/public/fonts/OpenSans-SemiboldItalic.woff)bin15736 -> 15736 bytes
-rw-r--r--web-ui/app/fonts/OpenSans.woff (renamed from web-ui/public/fonts/OpenSans.woff)bin14604 -> 14604 bytes
-rw-r--r--web-ui/app/fonts/OpenSansLight-Italic.woff (renamed from web-ui/public/fonts/OpenSansLight-Italic.woff)bin15956 -> 15956 bytes
-rw-r--r--web-ui/app/fonts/icomoon.ttf (renamed from web-ui/public/fonts/icomoon.ttf)bin1272 -> 1272 bytes
-rw-r--r--web-ui/app/fonts/icomoon.woff (renamed from web-ui/public/fonts/icomoon.woff)bin1348 -> 1348 bytes
-rw-r--r--web-ui/app/images/LOADING-transparent.gif (renamed from web-ui/src/images/LOADING-transparent.gif)bin16170 -> 16170 bytes
-rw-r--r--web-ui/app/images/fa-sent.svg (renamed from web-ui/src/images/fa-sent.svg)0
-rw-r--r--web-ui/app/images/favicon.png (renamed from web-ui/src/images/favicon.png)bin592 -> 592 bytes
-rw-r--r--web-ui/app/images/logo.svg (renamed from web-ui/src/images/logo.svg)0
-rw-r--r--web-ui/app/images/pixelated-symbol-blue-transparent-01.png (renamed from web-ui/src/images/pixelated-symbol-blue-transparent-01.png)bin9075 -> 9075 bytes
-rw-r--r--web-ui/app/index.html (renamed from service/templates/index.html)34
-rw-r--r--web-ui/app/js/dispatchers/left_pane_dispatcher.js (renamed from web-ui/public/js/dispatchers/left_pane_dispatcher.js)0
-rw-r--r--web-ui/app/js/dispatchers/middle_pane_dispatcher.js (renamed from web-ui/public/js/dispatchers/middle_pane_dispatcher.js)0
-rw-r--r--web-ui/app/js/dispatchers/right_pane_dispatcher.js (renamed from web-ui/public/js/dispatchers/right_pane_dispatcher.js)0
-rw-r--r--web-ui/app/js/features/features.js (renamed from web-ui/public/js/features/features.js)0
-rw-r--r--web-ui/app/js/feedback/feedback_cache.js (renamed from web-ui/public/js/feedback/feedback_cache.js)0
-rw-r--r--web-ui/app/js/feedback/feedback_trigger.js (renamed from web-ui/public/js/feedback/feedback_trigger.js)0
-rw-r--r--web-ui/app/js/foundation/initialize_foundation.js (renamed from web-ui/public/js/foundation/initialize_foundation.js)0
-rw-r--r--web-ui/app/js/foundation/off_canvas.js (renamed from web-ui/public/js/foundation/off_canvas.js)0
-rw-r--r--web-ui/app/js/helpers/browser.js (renamed from web-ui/public/js/helpers/browser.js)0
-rw-r--r--web-ui/app/js/helpers/contenttype.js (renamed from web-ui/public/js/helpers/contenttype.js)0
-rw-r--r--web-ui/app/js/helpers/iterator.js (renamed from web-ui/public/js/helpers/iterator.js)0
-rw-r--r--web-ui/app/js/helpers/monitored_ajax.js (renamed from web-ui/public/js/helpers/monitored_ajax.js)0
-rw-r--r--web-ui/app/js/helpers/sanitizer.js (renamed from web-ui/public/js/helpers/sanitizer.js)0
-rw-r--r--web-ui/app/js/helpers/triggering.js (renamed from web-ui/public/js/helpers/triggering.js)0
-rw-r--r--web-ui/app/js/helpers/view_helper.js (renamed from web-ui/public/js/helpers/view_helper.js)0
-rw-r--r--web-ui/app/js/lib/highlightRegex.js (renamed from web-ui/public/js/lib/highlightRegex.js)0
-rw-r--r--web-ui/app/js/lib/html4-defs.js (renamed from web-ui/public/js/lib/html4-defs.js)0
-rw-r--r--web-ui/app/js/mail_list/domain/refresher.js (renamed from web-ui/public/js/mail_list/domain/refresher.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_item_factory.js (renamed from web-ui/public/js/mail_list/ui/mail_item_factory.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/draft_item.js (renamed from web-ui/public/js/mail_list/ui/mail_items/draft_item.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js (renamed from web-ui/public/js/mail_list/ui/mail_items/generic_mail_item.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/mail_item.js (renamed from web-ui/public/js/mail_list/ui/mail_items/mail_item.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_items/sent_item.js (renamed from web-ui/public/js/mail_list/ui/mail_items/sent_item.js)0
-rw-r--r--web-ui/app/js/mail_list/ui/mail_list.js (renamed from web-ui/public/js/mail_list/ui/mail_list.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/archive_many_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/archive_many_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/compose_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/compose_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/delete_many_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/delete_many_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/mail_list_actions.js (renamed from web-ui/public/js/mail_list_actions/ui/mail_list_actions.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/mark_as_unread_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/mark_as_unread_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/mark_many_as_read_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/mark_many_as_read_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/pagination_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/pagination_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/recover_many_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/recover_many_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/refresh_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/refresh_trigger.js)0
-rw-r--r--web-ui/app/js/mail_list_actions/ui/toggle_check_all_trigger.js (renamed from web-ui/public/js/mail_list_actions/ui/toggle_check_all_trigger.js)0
-rw-r--r--web-ui/app/js/mail_view/data/feedback_sender.js (renamed from web-ui/public/js/mail_view/data/feedback_sender.js)0
-rw-r--r--web-ui/app/js/mail_view/data/mail_builder.js (renamed from web-ui/public/js/mail_view/data/mail_builder.js)0
-rw-r--r--web-ui/app/js/mail_view/data/mail_sender.js (renamed from web-ui/public/js/mail_view/data/mail_sender.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/attachment_icon.js (renamed from web-ui/public/js/mail_view/ui/attachment_icon.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/attachment_list.js (renamed from web-ui/public/js/mail_view/ui/attachment_list.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/compose_box.js (renamed from web-ui/public/js/mail_view/ui/compose_box.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/draft_box.js (renamed from web-ui/public/js/mail_view/ui/draft_box.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/draft_save_status.js (renamed from web-ui/public/js/mail_view/ui/draft_save_status.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/feedback_box.js (renamed from web-ui/public/js/mail_view/ui/feedback_box.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/forward_box.js (renamed from web-ui/public/js/mail_view/ui/forward_box.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/mail_actions.js (renamed from web-ui/public/js/mail_view/ui/mail_actions.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/mail_view.js (renamed from web-ui/public/js/mail_view/ui/mail_view.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/no_mails_available_pane.js (renamed from web-ui/public/js/mail_view/ui/no_mails_available_pane.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/no_message_selected_pane.js (renamed from web-ui/public/js/mail_view/ui/no_message_selected_pane.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/recipients/recipient.js (renamed from web-ui/public/js/mail_view/ui/recipients/recipient.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/recipients/recipients.js (renamed from web-ui/public/js/mail_view/ui/recipients/recipients.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/recipients/recipients_input.js (renamed from web-ui/public/js/mail_view/ui/recipients/recipients_input.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/recipients/recipients_iterator.js (renamed from web-ui/public/js/mail_view/ui/recipients/recipients_iterator.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/reply_box.js (renamed from web-ui/public/js/mail_view/ui/reply_box.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/reply_section.js (renamed from web-ui/public/js/mail_view/ui/reply_section.js)0
-rw-r--r--web-ui/app/js/mail_view/ui/send_button.js (renamed from web-ui/public/js/mail_view/ui/send_button.js)0
-rw-r--r--web-ui/app/js/main.js (renamed from web-ui/public/js/main.js)2
-rw-r--r--web-ui/app/js/mixins/with_auto_refresh.js (renamed from web-ui/public/js/mixins/with_auto_refresh.js)0
-rw-r--r--web-ui/app/js/mixins/with_compose_inline.js (renamed from web-ui/public/js/mixins/with_compose_inline.js)0
-rw-r--r--web-ui/app/js/mixins/with_enable_disable_on_event.js (renamed from web-ui/public/js/mixins/with_enable_disable_on_event.js)0
-rw-r--r--web-ui/app/js/mixins/with_feature_toggle.js (renamed from web-ui/public/js/mixins/with_feature_toggle.js)0
-rw-r--r--web-ui/app/js/mixins/with_hide_and_show.js (renamed from web-ui/public/js/mixins/with_hide_and_show.js)0
-rw-r--r--web-ui/app/js/mixins/with_mail_edit_base.js (renamed from web-ui/public/js/mixins/with_mail_edit_base.js)0
-rw-r--r--web-ui/app/js/mixins/with_mail_sandbox.js (renamed from web-ui/public/js/mixins/with_mail_sandbox.js)0
-rw-r--r--web-ui/app/js/mixins/with_mail_tagging.js (renamed from web-ui/public/js/mixins/with_mail_tagging.js)0
-rw-r--r--web-ui/app/js/monkey_patching/all.js (renamed from web-ui/public/js/monkey_patching/all.js)0
-rw-r--r--web-ui/app/js/monkey_patching/array.js (renamed from web-ui/public/js/monkey_patching/array.js)0
-rw-r--r--web-ui/app/js/monkey_patching/post_message.js (renamed from web-ui/public/js/monkey_patching/post_message.js)0
-rw-r--r--web-ui/app/js/page/default.js (renamed from web-ui/public/js/page/default.js)2
-rw-r--r--web-ui/app/js/page/events.js (renamed from web-ui/public/js/page/events.js)0
-rw-r--r--web-ui/app/js/page/logout.js (renamed from web-ui/public/js/page/logout.js)0
-rw-r--r--web-ui/app/js/page/logout_shortcut.js (renamed from web-ui/public/js/page/logout_shortcut.js)0
-rw-r--r--web-ui/app/js/page/pane_contract_expand.js (renamed from web-ui/public/js/page/pane_contract_expand.js)0
-rw-r--r--web-ui/app/js/page/pix_logo.js (renamed from web-ui/public/js/page/pix_logo.js)0
-rw-r--r--web-ui/app/js/page/router.js (renamed from web-ui/public/js/page/router.js)0
-rw-r--r--web-ui/app/js/page/router/url_params.js (renamed from web-ui/public/js/page/router/url_params.js)0
-rw-r--r--web-ui/app/js/page/unread_count_title.js (renamed from web-ui/public/js/page/unread_count_title.js)0
-rw-r--r--web-ui/app/js/page/version.js (renamed from web-ui/public/js/page/version.js)0
-rw-r--r--web-ui/app/js/sandbox.js (renamed from web-ui/public/js/sandbox.js)0
-rw-r--r--web-ui/app/js/search/results_highlighter.js (renamed from web-ui/public/js/search/results_highlighter.js)0
-rw-r--r--web-ui/app/js/search/search_trigger.js (renamed from web-ui/public/js/search/search_trigger.js)0
-rw-r--r--web-ui/app/js/services/delete_service.js (renamed from web-ui/public/js/services/delete_service.js)0
-rw-r--r--web-ui/app/js/services/mail_service.js (renamed from web-ui/public/js/services/mail_service.js)0
-rw-r--r--web-ui/app/js/services/model/mail.js (renamed from web-ui/public/js/services/model/mail.js)0
-rw-r--r--web-ui/app/js/services/recover_service.js (renamed from web-ui/public/js/services/recover_service.js)0
-rw-r--r--web-ui/app/js/style_guide/main.js (renamed from web-ui/public/js/style_guide/main.js)0
-rw-r--r--web-ui/app/js/tags/data/tags.js (renamed from web-ui/public/js/tags/data/tags.js)0
-rw-r--r--web-ui/app/js/tags/ui/tag.js (renamed from web-ui/public/js/tags/ui/tag.js)0
-rw-r--r--web-ui/app/js/tags/ui/tag_base.js (renamed from web-ui/public/js/tags/ui/tag_base.js)0
-rw-r--r--web-ui/app/js/tags/ui/tag_list.js (renamed from web-ui/public/js/tags/ui/tag_list.js)0
-rw-r--r--web-ui/app/js/user_alerts/ui/user_alerts.js (renamed from web-ui/public/js/user_alerts/ui/user_alerts.js)0
-rw-r--r--web-ui/app/js/user_settings/data/user_settings.js (renamed from web-ui/public/js/user_settings/data/user_settings.js)0
-rw-r--r--web-ui/app/js/user_settings/ui/user_settings_box.js (renamed from web-ui/public/js/user_settings/ui/user_settings_box.js)0
-rw-r--r--web-ui/app/js/user_settings/ui/user_settings_icon.js (renamed from web-ui/public/js/user_settings/ui/user_settings_icon.js)0
-rw-r--r--web-ui/app/js/views/i18n.js (renamed from web-ui/public/js/views/i18n.js)0
-rw-r--r--web-ui/app/js/views/recipientListFormatter.js (renamed from web-ui/public/js/views/recipientListFormatter.js)0
-rw-r--r--web-ui/app/js/views/templates.js85
-rw-r--r--web-ui/app/locales/en_US/translation.json (renamed from web-ui/public/locales/en_US/translation.json)0
-rw-r--r--web-ui/app/locales/pt_BR/translation.json (renamed from web-ui/public/locales/pt_BR/translation.json)0
-rw-r--r--web-ui/app/locales/sv_SE/translation.json (renamed from web-ui/public/locales/sv_SE/translation.json)0
-rw-r--r--web-ui/app/robots.txt (renamed from web-ui/public/robots.txt)0
-rw-r--r--web-ui/app/sandbox.html16
-rw-r--r--web-ui/app/scss/_mixins.scss (renamed from web-ui/public/scss/_mixins.scss)0
-rw-r--r--web-ui/app/scss/_others.scss (renamed from web-ui/public/scss/_others.scss)0
-rw-r--r--web-ui/app/scss/base/_colors.scss (renamed from web-ui/public/scss/base/_colors.scss)0
-rw-r--r--web-ui/app/scss/base/_fonts.scss (renamed from web-ui/public/scss/base/_fonts.scss)22
-rw-r--r--web-ui/app/scss/base/_scaffolding.scss (renamed from web-ui/public/scss/base/_scaffolding.scss)0
-rw-r--r--web-ui/app/scss/mixins/_position-helpers.scss (renamed from web-ui/public/scss/mixins/_position-helpers.scss)0
-rw-r--r--web-ui/app/scss/mixins/_tags.scss (renamed from web-ui/public/scss/mixins/_tags.scss)0
-rw-r--r--web-ui/app/scss/sandbox.scss (renamed from web-ui/public/scss/sandbox.scss)0
-rw-r--r--web-ui/app/scss/style.scss (renamed from web-ui/public/scss/style.scss)0
-rw-r--r--web-ui/app/scss/templates/_no-content-placeholder.scss (renamed from web-ui/public/scss/templates/_no-content-placeholder.scss)0
-rw-r--r--web-ui/app/scss/templates/_unread-count.scss (renamed from web-ui/public/scss/templates/_unread-count.scss)0
-rw-r--r--web-ui/app/scss/vendor/_customfont.scss (renamed from web-ui/public/scss/vendor/_customfont.scss)0
-rw-r--r--web-ui/app/scss/vendor/_foundation.scss (renamed from web-ui/public/scss/vendor/_foundation.scss)0
-rw-r--r--web-ui/app/scss/vendor/_reset.scss (renamed from web-ui/public/scss/vendor/_reset.scss)0
-rw-r--r--web-ui/app/scss/vendor/_scut.scss (renamed from web-ui/public/scss/vendor/_scut.scss)0
-rw-r--r--web-ui/app/scss/views/_action-bar.scss (renamed from web-ui/public/scss/views/_action-bar.scss)0
-rw-r--r--web-ui/app/scss/views/_close-button.scss (renamed from web-ui/public/scss/views/_close-button.scss)0
-rw-r--r--web-ui/app/scss/views/_compose-button.scss (renamed from web-ui/public/scss/views/_compose-button.scss)0
-rw-r--r--web-ui/app/scss/views/_compose-view.scss (renamed from web-ui/public/scss/views/_compose-view.scss)0
-rw-r--r--web-ui/app/scss/views/_mail-list.scss (renamed from web-ui/public/scss/views/_mail-list.scss)0
-rw-r--r--web-ui/app/scss/views/_message-panel.scss (renamed from web-ui/public/scss/views/_message-panel.scss)0
-rw-r--r--web-ui/app/scss/views/_navigation.scss (renamed from web-ui/public/scss/views/_navigation.scss)0
-rw-r--r--web-ui/app/scss/views/_no-mails-available.scss (renamed from web-ui/public/scss/views/_no-mails-available.scss)0
-rw-r--r--web-ui/app/scss/views/_no-message-selected.scss (renamed from web-ui/public/scss/views/_no-message-selected.scss)0
-rw-r--r--web-ui/app/scss/views/_read-view.scss (renamed from web-ui/public/scss/views/_read-view.scss)0
-rw-r--r--web-ui/app/scss/views/_security-labels.scss (renamed from web-ui/public/scss/views/_security-labels.scss)0
-rw-r--r--web-ui/app/templates/compose/attachment_item.hbs (renamed from web-ui/public/templates/compose/attachment_item.hbs)0
-rw-r--r--web-ui/app/templates/compose/attachment_upload_item.hbs (renamed from web-ui/public/templates/compose/attachment_upload_item.hbs)0
-rw-r--r--web-ui/app/templates/compose/attachments_list.hbs (renamed from web-ui/public/templates/compose/attachments_list.hbs)0
-rw-r--r--web-ui/app/templates/compose/compose_box.hbs (renamed from web-ui/public/templates/compose/compose_box.hbs)0
-rw-r--r--web-ui/app/templates/compose/feedback_box.hbs (renamed from web-ui/public/templates/compose/feedback_box.hbs)0
-rw-r--r--web-ui/app/templates/compose/fixed_recipient.hbs (renamed from web-ui/public/templates/compose/fixed_recipient.hbs)0
-rw-r--r--web-ui/app/templates/compose/inline_box.hbs (renamed from web-ui/public/templates/compose/inline_box.hbs)0
-rw-r--r--web-ui/app/templates/compose/no_mails_available.hbs (renamed from web-ui/public/templates/compose/no_mails_available.hbs)0
-rw-r--r--web-ui/app/templates/compose/no_message_selected.hbs (renamed from web-ui/public/templates/compose/no_message_selected.hbs)0
-rw-r--r--web-ui/app/templates/compose/recipient_input.hbs (renamed from web-ui/public/templates/compose/recipient_input.hbs)0
-rw-r--r--web-ui/app/templates/compose/recipients.hbs (renamed from web-ui/public/templates/compose/recipients.hbs)0
-rw-r--r--web-ui/app/templates/compose/reply_section.hbs (renamed from web-ui/public/templates/compose/reply_section.hbs)0
-rw-r--r--web-ui/app/templates/compose/upload_attachment_failed.hbs (renamed from web-ui/public/templates/compose/upload_attachment_failed.hbs)0
-rw-r--r--web-ui/app/templates/feedback/feedback_trigger.hbs (renamed from web-ui/public/templates/feedback/feedback_trigger.hbs)0
-rw-r--r--web-ui/app/templates/mail_actions/actions_box.hbs (renamed from web-ui/public/templates/mail_actions/actions_box.hbs)0
-rw-r--r--web-ui/app/templates/mail_actions/compose_trigger.hbs (renamed from web-ui/public/templates/mail_actions/compose_trigger.hbs)0
-rw-r--r--web-ui/app/templates/mail_actions/pagination_trigger.hbs (renamed from web-ui/public/templates/mail_actions/pagination_trigger.hbs)0
-rw-r--r--web-ui/app/templates/mail_actions/refresh_trigger.hbs (renamed from web-ui/public/templates/mail_actions/refresh_trigger.hbs)0
-rw-r--r--web-ui/app/templates/mail_actions/trash_actions_box.hbs (renamed from web-ui/public/templates/mail_actions/trash_actions_box.hbs)0
-rw-r--r--web-ui/app/templates/mails/draft.hbs (renamed from web-ui/public/templates/mails/draft.hbs)0
-rw-r--r--web-ui/app/templates/mails/full_view.hbs (renamed from web-ui/public/templates/mails/full_view.hbs)0
-rw-r--r--web-ui/app/templates/mails/mail_actions.hbs (renamed from web-ui/public/templates/mails/mail_actions.hbs)0
-rw-r--r--web-ui/app/templates/mails/sent.hbs (renamed from web-ui/public/templates/mails/sent.hbs)0
-rw-r--r--web-ui/app/templates/mails/single.hbs (renamed from web-ui/public/templates/mails/single.hbs)0
-rw-r--r--web-ui/app/templates/mails/trash.hbs (renamed from web-ui/public/templates/mails/trash.hbs)0
-rw-r--r--web-ui/app/templates/page/logout.hbs (renamed from web-ui/public/templates/page/logout.hbs)0
-rw-r--r--web-ui/app/templates/page/logout_shortcut.hbs (renamed from web-ui/public/templates/page/logout_shortcut.hbs)0
-rw-r--r--web-ui/app/templates/page/user_settings_box.hbs (renamed from web-ui/public/templates/page/user_settings_box.hbs)0
-rw-r--r--web-ui/app/templates/page/user_settings_icon.hbs (renamed from web-ui/public/templates/page/user_settings_icon.hbs)0
-rw-r--r--web-ui/app/templates/page/version.hbs (renamed from web-ui/public/templates/page/version.hbs)0
-rw-r--r--web-ui/app/templates/search/search_trigger.hbs (renamed from web-ui/public/templates/search/search_trigger.hbs)0
-rw-r--r--web-ui/app/templates/tags/shortcut.hbs (renamed from web-ui/public/templates/tags/shortcut.hbs)0
-rw-r--r--web-ui/app/templates/tags/tag.hbs (renamed from web-ui/public/templates/tags/tag.hbs)0
-rw-r--r--web-ui/app/templates/tags/tag_inner.hbs (renamed from web-ui/public/templates/tags/tag_inner.hbs)0
-rw-r--r--web-ui/app/templates/tags/tag_list.hbs (renamed from web-ui/public/templates/tags/tag_list.hbs)0
-rw-r--r--web-ui/app/templates/user_alerts/message.hbs (renamed from web-ui/public/templates/user_alerts/message.hbs)0
-rwxr-xr-xweb-ui/config/add_git_version.sh2
-rw-r--r--web-ui/config/buildoptions.js4
-rw-r--r--web-ui/config/compass.rb12
-rw-r--r--web-ui/config/control-tower.yml2
-rw-r--r--web-ui/config/imagemin.js4
-rw-r--r--web-ui/config/minify_app.sh34
-rw-r--r--web-ui/config/package.sh54
-rw-r--r--web-ui/karma.conf.js54
-rw-r--r--web-ui/package.json35
-rw-r--r--web-ui/public/dummy.json1
-rw-r--r--web-ui/public/js/views/templates.js85
-rw-r--r--web-ui/public/sandbox.html13
-rw-r--r--web-ui/public/signup.css174
-rw-r--r--web-ui/public/signup.html19
-rw-r--r--web-ui/src/images/pixelated-logo-orange.svg29
-rw-r--r--web-ui/src/images/sent_email.pngbin9160 -> 0 bytes
-rw-r--r--web-ui/src/js/index.js235
-rw-r--r--web-ui/test/test-main.js54
257 files changed, 556 insertions, 1475 deletions
diff --git a/.gitignore b/.gitignore
index 7b1d856c..0c347bf8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,37 +3,35 @@
*.log
*.DS_Store
*.egg-info
-/web-ui/lib/
-/web-ui/node_modules
-/web-ui/public/bower_components/
-/web-ui/public/images/
-/web-ui/public/signup.js
-/web-ui/public/*.min.js
+web-ui/node_modules
+web-ui/app/bower_components
+web-ui/target
.tmp
.sass-cache/
+dist/
*archive.zip
*.swp
*.swo
-/web-ui/public/js/generated
-/web-ui/public/css
+web-ui/app/js/generated
+web-ui/app/css
test-results.xml
-/control_tower.html
-/state.yml
-*.pid
+control_tower.html
+state.yml
+.server.pid
*archive.zip
artifacts/
-/public/
+public/
.DS_Store
-/screenshot*
+screenshot*
*.pyc
-/env/
+env/
.vagrant/
__pycache__/
.virtualenv
# custom config file that can be used with the useragent
/config
-/credentials.ini
-/pixelated.cfg
-/service/_trial_temp/
-/_trial_temp
-/web-ui/coverage
+credentials.ini
+pixelated.cfg
+service/_trial_temp/
+_trial_temp
+web-ui/coverage
diff --git a/README.md b/README.md
index 50c7cda9..a3232039 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ Here's a [podcast](https://soundcloud.com/thoughtworks/pixelated-why-secure-comm
**Pixelated is still in early development state!**
-![High level architecture User Agent](https://raw.githubusercontent.com/pixelated/website/master/static/images/pixelated-user-agent.png)
+![High level architecture User Agent](https://raw.githubusercontent.com/pixelated/website/master/assets/images/pixelated-user-agent.png)
## Try it!
diff --git a/doc/first-steps.md b/doc/first-steps.md
index 0485b236..e4a24097 100644
--- a/doc/first-steps.md
+++ b/doc/first-steps.md
@@ -55,7 +55,7 @@ After that take some minutes to familiarize yourself with the user interface.
To get a better feeling for the code base, let's try some smaller changes. Let's assume that we'd like to change the way subjects are displayed in the mail list.
First we want to find the location in the code that renders the subjects.
-Start your favorite text editor and open pixelated-user-agent/web-ui/public/js/mail_list/ui/mail_items/mail_item.js. Find the method named render. This seems to be the right location. To verify our assumption, let's change the html content.
+Start your favorite text editor and open pixelated-user-agent/web-ui/app/js/mail_list/ui/mail_items/mail_item.js. Find the method named render. This seems to be the right location. To verify our assumption, let's change the html content.
```javascript
this.render = function () {
@@ -139,7 +139,7 @@ cd web-ui
Now refresh your browser again to see the changes in effect.
Finally we would like to change the color of the highlighting. The pixleated user agent uses [SASS](http://sass-lang.com/) to make handling styles a little bit easier.
-You can find the style sheets in web-ui/public/scss/. The search-hightlight is defined in styles.scss:
+You can find the style sheets in web-ui/app/scss/. The search-hightlight is defined in styles.scss:
```scss
.search-highlight {
diff --git a/service/MANIFEST.in b/service/MANIFEST.in
index 81d25913..a4fb90be 100644
--- a/service/MANIFEST.in
+++ b/service/MANIFEST.in
@@ -1,5 +1,5 @@
include README.md
recursive-include pixelated/certificates *.*
-recursive-include pixelated/static *.*
+recursive-include pixelated/assets *.*
recursive-include debian *
diff --git a/service/go b/service/go
index 904cb17b..eae21a2e 100755
--- a/service/go
+++ b/service/go
@@ -38,11 +38,11 @@ function setuppy {
echo "Installing Pixelated User Agent."
pip install --upgrade pip setuptools
if [ `uname -s` = "Darwin" ]; then
- CFLAGS="-DCRYPTOPP_DISABLE_ASM=1" pip install --exists-action w -r requirements.txt
+ CFLAGS="-DCRYPTOPP_DISABLE_ASM=1" pip install --exists-action s -r requirements.txt
else
- pip install --exists-action w -r requirements.txt
+ pip install --exists-action s -r requirements.txt
fi
- pip install --exists-action w -r test_requirements.txt
+ pip install --exists-action s -r test_requirements.txt
echo "Done."
}
diff --git a/service/pixelated/adapter/welcome_mail.py b/service/pixelated/adapter/welcome_mail.py
index 50147990..8d3cdd7a 100644
--- a/service/pixelated/adapter/welcome_mail.py
+++ b/service/pixelated/adapter/welcome_mail.py
@@ -20,7 +20,7 @@ from pixelated.adapter.model.mail import InputMail
def add_welcome_mail(mail_store, language='en-US'):
welcome_mail = pkg_resources.resource_filename(
- 'templates',
+ 'pixelated.assets',
'welcome.mail.%s' % (language))
with open(welcome_mail) as mail_template_file:
diff --git a/service/pixelated/application.py b/service/pixelated/application.py
index 73095da4..46e5ba85 100644
--- a/service/pixelated/application.py
+++ b/service/pixelated/application.py
@@ -37,18 +37,12 @@ from pixelated.config.leap import initialize_leap_single_user, init_monkeypatche
from pixelated.config.services import ServicesFactory, SingleUserServicesFactory
from pixelated.config.site import PixelatedSite
from pixelated.resources.auth import PixelatedRealm, PixelatedAuthSessionWrapper, SessionChecker
+from pixelated.resources.login_resource import LoginResource
from pixelated.resources.root_resource import RootResource
log = Logger()
-def get_static_folder():
- static_folder = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "web-ui", "public"))
- if not os.path.exists(static_folder):
- static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
- return static_folder
-
-
class UserAgentMode(object):
def __init__(self, is_single_user):
self.is_single_user = is_single_user
@@ -100,7 +94,7 @@ def initialize():
args = arguments.parse_user_agent_args()
logger.init(debug=args.debug)
services_factory = _create_service_factory(args)
- resource = RootResource(services_factory, static_folder=get_static_folder())
+ resource = RootResource(services_factory)
def start():
start_async = _start_mode(args, resource, services_factory)
@@ -161,12 +155,11 @@ def _setup_multi_user(args, root_resource, services_factory):
def set_up_protected_resources(root_resource, provider, services_factory, banner=None, authenticator=None):
session_checker = SessionChecker(services_factory)
- anonymous_resource = RootResource(services_factory, static_folder=get_static_folder(), public=True)
- realm = PixelatedRealm(root_resource, anonymous_resource)
+ realm = PixelatedRealm()
_portal = portal.Portal(realm, [session_checker, AllowAnonymousAccess()])
- protected_resource = PixelatedAuthSessionWrapper(_portal)
- anonymous_resource.initialize(provider, disclaimer_banner=banner, authenticator=authenticator)
+ anonymous_resource = LoginResource(services_factory, provider, disclaimer_banner=banner, authenticator=authenticator)
+ protected_resource = PixelatedAuthSessionWrapper(_portal, root_resource, anonymous_resource, [])
root_resource.initialize(provider, disclaimer_banner=banner, authenticator=authenticator)
return protected_resource
diff --git a/service/templates/Interstitial.html b/service/pixelated/assets/Interstitial.html
index 7787a1c5..bc6cc738 100644
--- a/service/templates/Interstitial.html
+++ b/service/pixelated/assets/Interstitial.html
@@ -4,15 +4,15 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
- <script src="static/snap.svg-min.js"></script>
- <script src="static/jquery-2.1.3.min.js"></script>
+ <script src="startup-assets/snap.svg-min.js"></script>
+ <script src="startup-assets/jquery-2.1.3.min.js"></script>
</head>
<body style="border: 0px; padding: 0px; margin: 0px;background-color: #808181">
<section id="hive-section" style="background-color: #808181;" name="hive-section">
<svg id="hive" style="width: 100%; height: 100%;"></svg>
</section>
- <script src="static/Interstitial.js"></script>
+ <script src="startup-assets/Interstitial.js"></script>
</body>
</html>
diff --git a/web-ui/public/Interstitial.js b/service/pixelated/assets/Interstitial.js
index 05c5ff29..ac5a789a 100644
--- a/web-ui/public/Interstitial.js
+++ b/service/pixelated/assets/Interstitial.js
@@ -1,7 +1,7 @@
if ($('#hive').length) {
var hive = new Snap('#hive');
var img_width = $('#hive').width();
- var left_pos = img_width * 0.5;
+ var left_pos = img_width * .5;
var pixelated = hive.path("M12.4,20.3v31.8l28,15.8l28-15.8V20.3l-28-15.8L12.4,20.3z M39.2,56.4l-16.3-9V27.9l16.3,9.3L39.2,56.4z M57.7,47.4l-16.1,9l0-19.2l16.1-9.4V47.4z M57.7,25.2L40.4,35.5L22.9,25.2l17.5-9.4L57.7,25.2z").transform("translate(319, 50)").attr("fill", "#908e8e");
var all = hive.group().transform("matrix(2, 0, 0, 2, -100, -100)");
@@ -14,8 +14,8 @@ if ($('#hive').length) {
for (var j = 0; j < rows; j++) {
for (var i = 0; i < cols; i++) {
- var x = i * width + (j%2*width/2);
- var y = j * height;
+ x = i * width + (j%2*width/2);
+ y = j * height;
all.add(pixelated.clone().transform("translate("+x+","+y+")"));
}
}
@@ -23,7 +23,6 @@ if ($('#hive').length) {
all.add(pixelated);
var brightenLogo = function () {
- 'use strict';
var glowPosition = Math.floor(Math.random()*rows*cols);
all[glowPosition].animate({fill: "#FFF"}, 1000, function() {
@@ -32,7 +31,6 @@ if ($('#hive').length) {
};
var darkenLogo = function (el) {
- 'use strict';
el.animate({fill: "#908e8e"}, 1000, brightenLogo);
};
@@ -41,7 +39,6 @@ if ($('#hive').length) {
}
$(function () {
- 'use strict';
var handler = setInterval(function () {
$.ajax({
method: 'GET',
diff --git a/service/templates/__init__.py b/service/pixelated/assets/__init__.py
index e69de29b..e69de29b 100644
--- a/service/templates/__init__.py
+++ b/service/pixelated/assets/__init__.py
diff --git a/service/templates/_login_disclaimer_banner.html b/service/pixelated/assets/_login_disclaimer_banner.html
index dfc63030..dfc63030 100644
--- a/service/templates/_login_disclaimer_banner.html
+++ b/service/pixelated/assets/_login_disclaimer_banner.html
diff --git a/web-ui/public/favicon.png b/service/pixelated/assets/favicon.png
index e14841c7..e14841c7 100644
--- a/web-ui/public/favicon.png
+++ b/service/pixelated/assets/favicon.png
Binary files differ
diff --git a/web-ui/public/hive-bg.png b/service/pixelated/assets/hive-bg.png
index 77316967..77316967 100644
--- a/web-ui/public/hive-bg.png
+++ b/service/pixelated/assets/hive-bg.png
Binary files differ
diff --git a/service/pixelated/assets/index.html b/service/pixelated/assets/index.html
new file mode 100644
index 00000000..c095577e
--- /dev/null
+++ b/service/pixelated/assets/index.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta http-equiv="refresh" content="0;URL=/login">
+ </head>
+ <body bgcolor="#FFFFFF" text="#000000\">
+ <a href="/login">click here</a>
+ </body>
+</html>
+
diff --git a/web-ui/public/jquery-2.1.3.min.js b/service/pixelated/assets/jquery-2.1.3.min.js
index 25714ed2..25714ed2 100644
--- a/web-ui/public/jquery-2.1.3.min.js
+++ b/service/pixelated/assets/jquery-2.1.3.min.js
diff --git a/service/templates/login.html b/service/pixelated/assets/login.html
index c60e9305..ff103f03 100644
--- a/service/templates/login.html
+++ b/service/pixelated/assets/login.html
@@ -3,22 +3,21 @@
<head>
<title>Pixelated - Login</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <link rel="icon" type="image/png" href="/static/favicon.png" />
- <link rel="stylesheet" type="text/css" href="/static/normalize.min.css" />
- <link rel="stylesheet" type="text/css" href="/static/pixelated.css" />
- <link rel="stylesheet" type="text/css" href="/static/opensans.css" />
+ <link rel="icon" type="image/png" href="/startup-assets/favicon.png" />
+ <link rel="stylesheet" type="text/css" href="/startup-assets/normalize.min.css" />
+ <link rel="stylesheet" type="text/css" href="/startup-assets/pixelated.css" />
+ <link rel="stylesheet" type="text/css" href="/startup-assets/opensans.css" />
</head>
<body>
<div class="content">
<div class="login">
- <img class="logo" src="/static/pixelated-logo-orange.svg" alt="Pixelated logo"/>
+ <img class="logo" src="/startup-assets/pixelated-logo-orange.svg" alt="Pixelated logo"/>
<p t:render="error_msg" class="error" ></p>
<form class="standard" id="login_form" action="/login" method="post">
- <input t:render="csrftoken" type="hidden" name="csrftoken" id="csrftoken"><t:attr name="value"><t:slot name="csrftoken" /></t:attr></input>
<input type="text" name="username" id="email" class="text-field" placeholder="username" tabindex="1"
autofocus="" />
<input type="password" name="password" id="password" class="text-field" placeholder="password"
diff --git a/web-ui/public/normalize.min.css b/service/pixelated/assets/normalize.min.css
index d3c7f4d5..d3c7f4d5 100644
--- a/web-ui/public/normalize.min.css
+++ b/service/pixelated/assets/normalize.min.css
diff --git a/web-ui/public/opensans.css b/service/pixelated/assets/opensans.css
index a42f346c..a42f346c 100644
--- a/web-ui/public/opensans.css
+++ b/service/pixelated/assets/opensans.css
diff --git a/web-ui/public/pixelated-logo-orange.svg b/service/pixelated/assets/pixelated-logo-orange.svg
index 7e0ef43d..7e0ef43d 100644
--- a/web-ui/public/pixelated-logo-orange.svg
+++ b/service/pixelated/assets/pixelated-logo-orange.svg
diff --git a/web-ui/public/pixelated.css b/service/pixelated/assets/pixelated.css
index b3e1d16e..b3e1d16e 100644
--- a/web-ui/public/pixelated.css
+++ b/service/pixelated/assets/pixelated.css
diff --git a/web-ui/public/snap.svg-min.js b/service/pixelated/assets/snap.svg-min.js
index ca9601ab..ca9601ab 100644
--- a/web-ui/public/snap.svg-min.js
+++ b/service/pixelated/assets/snap.svg-min.js
diff --git a/service/templates/welcome.mail.en-US b/service/pixelated/assets/welcome.mail.en-US
index c8aa1359..c8aa1359 100644
--- a/service/templates/welcome.mail.en-US
+++ b/service/pixelated/assets/welcome.mail.en-US
diff --git a/service/templates/welcome.mail.pt-BR b/service/pixelated/assets/welcome.mail.pt-BR
index 41dc846f..41dc846f 100644
--- a/service/templates/welcome.mail.pt-BR
+++ b/service/pixelated/assets/welcome.mail.pt-BR
diff --git a/service/templates/welcome.mail.pt-BR.txt b/service/pixelated/assets/welcome.mail.pt-BR.txt
index 3a59f51d..3a59f51d 100644
--- a/service/templates/welcome.mail.pt-BR.txt
+++ b/service/pixelated/assets/welcome.mail.pt-BR.txt
diff --git a/service/pixelated/bitmask_libraries/provider.py b/service/pixelated/bitmask_libraries/provider.py
index bc19f79e..96935fbc 100644
--- a/service/pixelated/bitmask_libraries/provider.py
+++ b/service/pixelated/bitmask_libraries/provider.py
@@ -193,7 +193,7 @@ class LeapProvider(object):
fin.close()
def setup_ca_bundle(self):
- path = os.path.dirname(self.provider_api_cert)
+ path = os.path.join(leap_config.leap_home, 'providers', self.server_name, 'keys', 'client')
if not os.path.isdir(path):
os.makedirs(path, 0700)
self._download_cert(self.provider_api_cert)
diff --git a/service/pixelated/resources/__init__.py b/service/pixelated/resources/__init__.py
index 023758de..11611f0b 100644
--- a/service/pixelated/resources/__init__.py
+++ b/service/pixelated/resources/__init__.py
@@ -13,9 +13,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
+
import json
-import os
from twisted.web.http import UNAUTHORIZED
from twisted.web.resource import Resource
@@ -27,8 +26,6 @@ from twisted.web.http import INTERNAL_SERVER_ERROR, SERVICE_UNAVAILABLE
log = Logger()
-CSRF_TOKEN_LENGTH = 32
-
class SetEncoder(json.JSONEncoder):
def default(self, obj):
@@ -65,11 +62,6 @@ class BaseResource(Resource):
Resource.__init__(self)
self._services_factory = services_factory
- def _add_csrf_cookie(self, request):
- csrf_token = IPixelatedSession(request.getSession()).get_csrf_token()
- request.addCookie('XSRF-TOKEN', csrf_token)
- log.debug('XSRF-TOKEN added: %s' % csrf_token)
-
def _get_user_id_from_request(self, request):
if self._services_factory.mode.is_single_user:
return None # it doesn't matter
diff --git a/service/pixelated/resources/auth.py b/service/pixelated/resources/auth.py
index 057eb053..adac985f 100644
--- a/service/pixelated/resources/auth.py
+++ b/service/pixelated/resources/auth.py
@@ -64,18 +64,10 @@ class SessionChecker(object):
class PixelatedRealm(object):
implements(portal.IRealm)
- def __init__(self, authenticated_resource, public_resource):
- self._authenticated_resource = authenticated_resource
- self._public_resource = public_resource
-
def requestAvatar(self, avatarId, mind, *interfaces):
- if IResource not in interfaces:
- raise NotImplementedError()
- if avatarId == checkers.ANONYMOUS:
- avatar = self._public_resource
- else:
- avatar = self._authenticated_resource
- return IResource, avatar, lambda: None
+ if IResource in interfaces:
+ return IResource, avatarId, lambda: None
+ raise NotImplementedError()
@implementer(IResource)
@@ -83,9 +75,11 @@ class PixelatedAuthSessionWrapper(object):
isLeaf = False
- def __init__(self, portal, credentialFactories=[]):
+ def __init__(self, portal, root_resource, anonymous_resource, credentialFactories):
self._portal = portal
self._credentialFactories = credentialFactories
+ self._root_resource = root_resource
+ self._anonymous_resource = anonymous_resource
def render(self, request):
raise UnsupportedMethod(())
@@ -99,17 +93,23 @@ class PixelatedAuthSessionWrapper(object):
return util.DeferredResource(self._login(creds, request))
def _login(self, credentials, request):
+ pattern = re.compile("^/sandbox/")
+
def loginSucceeded(args):
interface, avatar, logout = args
- return avatar
+ if avatar == checkers.ANONYMOUS and not pattern.match(request.path):
+ return self._anonymous_resource
+ else:
+ return self._root_resource
def loginFailed(result):
if result.check(error.Unauthorized, error.LoginFailed):
return UnauthorizedResource(self._credentialFactories)
else:
- log.error(
- "PixelatedAuthSessionWrapper.getChildWithDefault encountered "
- "unexpected error: %s" % result)
+ log.err(
+ result,
+ "HTTPAuthSessionWrapper.getChildWithDefault encountered "
+ "unexpected error")
return ErrorPage(500, None, None)
d = self._portal.login(credentials, None, IResource)
diff --git a/service/pixelated/resources/inbox_resource.py b/service/pixelated/resources/inbox_resource.py
deleted file mode 100644
index d0096efe..00000000
--- a/service/pixelated/resources/inbox_resource.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (c) 2016 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
-import os
-import pkg_resources
-from string import Template
-
-import pixelated
-from pixelated.resources import BaseResource
-
-from twisted.logger import Logger
-
-logger = Logger()
-
-
-MODE_STARTUP = 1
-MODE_RUNNING = 2
-
-
-class InboxResource(BaseResource):
- isLeaf = True
-
- def __init__(self, services_factory):
- BaseResource.__init__(self, services_factory)
- with open(pkg_resources.resource_filename('templates', 'index.html')) as f:
- self._html_template = f.read()
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
- self.interstitial = f.read()
- self._mode = MODE_STARTUP
-
- def initialize(self):
- self._mode = MODE_RUNNING
-
- def _is_starting(self):
- return self._mode == MODE_STARTUP
-
- def render_GET(self, request):
- if self._is_starting():
- return self.interstitial
- else:
- account_email = self.mail_service(request).account_email
- response = Template(self._html_template).safe_substitute(account_email=account_email)
- return str(response)
diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py
index 9bb771df..ed0cb54e 100644
--- a/service/pixelated/resources/login_resource.py
+++ b/service/pixelated/resources/login_resource.py
@@ -15,7 +15,6 @@
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
import os
-import pkg_resources
from xml.sax import SAXParseException
from pixelated.authentication import Authenticator
@@ -35,6 +34,22 @@ from twisted.web.template import Element, XMLFile, renderElement, renderer
log = Logger()
+def _get_startup_folder():
+ path = os.path.dirname(os.path.abspath(__file__))
+ return os.path.join(path, '..', 'assets')
+
+
+def _get_static_folder():
+ static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app"))
+ # this is a workaround for packaging
+ if not os.path.exists(static_folder):
+ static_folder = os.path.abspath(
+ os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
+ return static_folder
+
+
def parse_accept_language(all_headers):
accepted_languages = ['pt-BR', 'en-US']
languages = all_headers.get('accept-language', '').split(';')[0]
@@ -45,7 +60,7 @@ def parse_accept_language(all_headers):
class DisclaimerElement(Element):
- loader = XMLFile(FilePath(pkg_resources.resource_filename('templates', '_login_disclaimer_banner.html')))
+ loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), '_login_disclaimer_banner.html')))
def __init__(self, banner):
super(DisclaimerElement, self).__init__()
@@ -68,7 +83,7 @@ class DisclaimerElement(Element):
class LoginWebSite(Element):
- loader = XMLFile(FilePath(pkg_resources.resource_filename('templates', 'login.html')))
+ loader = XMLFile(FilePath(os.path.join(_get_startup_folder(), 'login.html')))
def __init__(self, error_msg=None, disclaimer_banner_file=None):
super(LoginWebSite, self).__init__()
@@ -82,11 +97,6 @@ class LoginWebSite(Element):
return tag('')
@renderer
- def csrftoken(self, request, tag):
- tag.fillSlots(csrftoken=IPixelatedSession(request.getSession()).get_csrf_token())
- return tag
-
- @renderer
def disclaimer(self, request, tag):
return DisclaimerElement(self.disclaimer_banner_file).render(request)
@@ -96,12 +106,15 @@ class LoginResource(BaseResource):
def __init__(self, services_factory, provider=None, disclaimer_banner=None, authenticator=None):
BaseResource.__init__(self, services_factory)
+ self._static_folder = _get_static_folder()
+ self._startup_folder = _get_startup_folder()
self._disclaimer_banner = disclaimer_banner
self._provider = provider
self._authenticator = authenticator or Authenticator(provider)
self._bootstrap_user_services = BootstrapUserServices(services_factory, provider)
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
+ self.putChild('startup-assets', File(self._startup_folder))
+ with open(os.path.join(self._startup_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
def getChild(self, path, request):
@@ -114,7 +127,6 @@ class LoginResource(BaseResource):
return NoResource()
def render_GET(self, request):
- request.getSession()
request.setResponseCode(OK)
return self._render_template(request)
diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py
index 5cc93dbe..8df76c70 100644
--- a/service/pixelated/resources/root_resource.py
+++ b/service/pixelated/resources/root_resource.py
@@ -13,12 +13,12 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import hashlib
import json
import os
-import pkg_resources
+from string import Template
from pixelated.resources.users import UsersResource
-import pixelated
from pixelated.resources import BaseResource, UnAuthorizedResource, UnavailableResource
from pixelated.resources import IPixelatedSession
from pixelated.resources.attachments_resource import AttachmentsResource
@@ -33,42 +33,43 @@ from pixelated.resources.mail_resource import MailResource
from pixelated.resources.mails_resource import MailsResource
from pixelated.resources.tags_resource import TagsResource
from pixelated.resources.keys_resource import KeysResource
-from pixelated.resources.inbox_resource import InboxResource, MODE_STARTUP, MODE_RUNNING
from twisted.web.resource import NoResource
from twisted.web.static import File
-from twisted.web.util import Redirect
from twisted.logger import Logger
-logger = Logger()
+log = Logger()
-class RootResource(BaseResource):
+CSRF_TOKEN_LENGTH = 32
+
+MODE_STARTUP = 1
+MODE_RUNNING = 2
+
- def __init__(self, services_factory, static_folder, public=False):
+class RootResource(BaseResource):
+ def __init__(self, services_factory):
BaseResource.__init__(self, services_factory)
- self._public = public
- self._static_folder = static_folder
+ self._startup_assets_folder = self._get_startup_folder()
+ self._static_folder = self._get_static_folder()
+ self._html_template = open(os.path.join(self._static_folder, 'index.html')).read()
self._services_factory = services_factory
- with open(pkg_resources.resource_filename('templates', 'Interstitial.html')) as f:
+ self._child_resources = ChildResourcesMap()
+ with open(os.path.join(self._startup_assets_folder, 'Interstitial.html')) as f:
self.interstitial = f.read()
- self._redirect_to_login_resource = Redirect('login')
- self._inbox_resource = InboxResource(services_factory)
self._startup_mode()
def _startup_mode(self):
- self.putChildPublic('static', File(self._static_folder))
+ self.putChild('startup-assets', File(self._startup_assets_folder))
self._mode = MODE_STARTUP
- logger.debug('Root in STARTUP mode. %s' % self)
- def getChildWithDefault(self, path, request):
- self._add_csrf_cookie(request)
+ def getChild(self, path, request):
if path == '':
- return self._redirect_to_login_resource if self._public else self._inbox_resource
+ return self
if self._mode == MODE_STARTUP:
return UnavailableResource()
if self._is_xsrf_valid(request):
- return BaseResource.getChildWithDefault(self, path, request)
+ return self._child_resources.get(path)
return UnAuthorizedResource()
def _is_xsrf_valid(self, request):
@@ -77,7 +78,6 @@ class RootResource(BaseResource):
return True
xsrf_token = request.getCookie('XSRF-TOKEN')
- logger.debug('CSRF token: %s' % xsrf_token)
ajax_request = (request.getHeader('x-requested-with') == 'XMLHttpRequest')
if ajax_request:
@@ -87,32 +87,62 @@ class RootResource(BaseResource):
csrf_input = request.args.get('csrftoken', [None])[0] or json.loads(request.content.read()).get('csrftoken', [None])[0]
return csrf_input and csrf_input == xsrf_token
- def putChildPublic(self, path, resource):
- return BaseResource.putChild(self, path, resource)
+ def initialize(self, provider=None, disclaimer_banner=None, authenticator=None):
+ self._child_resources.add('sandbox', SandboxResource(self._static_folder))
+ self._child_resources.add('assets', File(self._static_folder))
+ self._child_resources.add('keys', KeysResource(self._services_factory))
+ self._child_resources.add(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
+ self._child_resources.add('contacts', ContactsResource(self._services_factory))
+ self._child_resources.add('features', FeaturesResource(provider))
+ self._child_resources.add('tags', TagsResource(self._services_factory))
+ self._child_resources.add('mails', MailsResource(self._services_factory))
+ self._child_resources.add('mail', MailResource(self._services_factory))
+ self._child_resources.add('feedback', FeedbackResource(self._services_factory))
+ self._child_resources.add('user-settings', UserSettingsResource(self._services_factory))
+ self._child_resources.add('users', UsersResource(self._services_factory))
+ self._child_resources.add(LoginResource.BASE_URL,
+ LoginResource(self._services_factory, provider, disclaimer_banner=disclaimer_banner, authenticator=authenticator))
+ self._child_resources.add(LogoutResource.BASE_URL, LogoutResource(self._services_factory))
- def putChildProtected(self, path, resource):
- return BaseResource.putChild(self, path, UnAuthorizedResource() if self._public else resource)
+ self._mode = MODE_RUNNING
- def putChild(self, path, resource):
- logger.warn('Use either `putChildPublic` or `putChildProtected` on this resource')
- return self.putChildProtected(path, resource) # to be on the safe side
+ def _get_startup_folder(self):
+ path = os.path.dirname(os.path.abspath(__file__))
+ return os.path.join(path, '..', 'assets')
- def initialize(self, provider=None, disclaimer_banner=None, authenticator=None):
- self.putChildPublic('sandbox', SandboxResource(self._static_folder))
- self.putChildProtected('keys', KeysResource(self._services_factory))
- self.putChildProtected(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
- self.putChildProtected('contacts', ContactsResource(self._services_factory))
- self.putChildProtected('features', FeaturesResource(provider))
- self.putChildProtected('tags', TagsResource(self._services_factory))
- self.putChildProtected('mails', MailsResource(self._services_factory))
- self.putChildProtected('mail', MailResource(self._services_factory))
- self.putChildProtected('feedback', FeedbackResource(self._services_factory))
- self.putChildProtected('user-settings', UserSettingsResource(self._services_factory))
- self.putChildProtected('users', UsersResource(self._services_factory))
- self.putChildPublic(LoginResource.BASE_URL,
- LoginResource(self._services_factory, provider, disclaimer_banner=disclaimer_banner, authenticator=authenticator))
- self.putChildPublic(LogoutResource.BASE_URL, LogoutResource(self._services_factory))
-
- self._inbox_resource.initialize()
- self._mode = MODE_RUNNING
- logger.debug('Root in RUNNING mode. %s' % self)
+ def _get_static_folder(self):
+ static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "web-ui", "app"))
+ # this is a workaround for packaging
+ if not os.path.exists(static_folder):
+ static_folder = os.path.abspath(
+ os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "app"))
+ if not os.path.exists(static_folder):
+ static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
+ return static_folder
+
+ def _is_starting(self):
+ return self._mode == MODE_STARTUP
+
+ def _add_csrf_cookie(self, request):
+ csrf_token = hashlib.sha256(os.urandom(CSRF_TOKEN_LENGTH)).hexdigest()
+ request.addCookie('XSRF-TOKEN', csrf_token)
+
+ def render_GET(self, request):
+ self._add_csrf_cookie(request)
+ if self._is_starting():
+ return self.interstitial
+ else:
+ account_email = self.mail_service(request).account_email
+ response = Template(self._html_template).safe_substitute(account_email=account_email)
+ return str(response)
+
+
+class ChildResourcesMap(object):
+ def __init__(self):
+ self._registry = {}
+
+ def add(self, path, resource):
+ self._registry[path] = resource
+
+ def get(self, path):
+ return self._registry.get(path) or NoResource()
diff --git a/service/pixelated/resources/session.py b/service/pixelated/resources/session.py
index 0e46ad8f..9ade8d29 100644
--- a/service/pixelated/resources/session.py
+++ b/service/pixelated/resources/session.py
@@ -13,15 +13,11 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-import hashlib
-import os
from zope.interface import Interface, Attribute, implements
from twisted.python.components import registerAdapter
from twisted.web.server import Session
-CSRF_TOKEN_LENGTH = 32
-
class IPixelatedSession(Interface):
user_uuid = Attribute('The uuid of the currently logged in user')
@@ -32,7 +28,6 @@ class PixelatedSession(object):
def __init__(self, session):
self.user_uuid = None
- self._csrf_token = None
def is_logged_in(self):
return self.user_uuid is not None
@@ -40,10 +35,5 @@ class PixelatedSession(object):
def expire(self):
self.user_uuid = None
- def get_csrf_token(self):
- if self._csrf_token is None:
- self._csrf_token = hashlib.sha256(os.urandom(CSRF_TOKEN_LENGTH)).hexdigest()
- return self._csrf_token
-
registerAdapter(PixelatedSession, Session, IPixelatedSession)
diff --git a/service/setup.py b/service/setup.py
index da706ed3..d7fd1607 100644
--- a/service/setup.py
+++ b/service/setup.py
@@ -41,11 +41,11 @@ setup(name='pixelated-user-agent',
'pixelated.adapter.mailstore.maintenance',
'pixelated.bitmask_libraries',
'pixelated.config',
+ 'pixelated.assets',
'pixelated.certificates',
'pixelated.support',
'pixelated.resources',
- 'pixelated.extensions',
- 'templates'
+ 'pixelated.extensions'
],
install_requires=[],
entry_points={
diff --git a/service/test/integration/test_contacts.py b/service/test/integration/test_contacts.py
index a890466f..946818fd 100644
--- a/service/test/integration/test_contacts.py
+++ b/service/test/integration/test_contacts.py
@@ -16,6 +16,7 @@
from test.support.integration import SoledadTestBase, MailBuilder
from twisted.internet import defer
import json
+import pkg_resources
class ContactsTest(SoledadTestBase):
diff --git a/service/test/integration/test_delete_mail.py b/service/test/integration/test_delete_mail.py
index 34ea5048..a912f9f0 100644
--- a/service/test/integration/test_delete_mail.py
+++ b/service/test/integration/test_delete_mail.py
@@ -15,7 +15,6 @@
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
from twisted.internet import defer
from test.support.integration import SoledadTestBase, MailBuilder
-from pixelated.resources import IPixelatedSession
class DeleteMailTest(SoledadTestBase):
@@ -28,8 +27,7 @@ class DeleteMailTest(SoledadTestBase):
inbox_mails = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertEquals(1, len(inbox_mails))
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- yield self.app_test_client.delete_mail(mail.mail_id, session=first_request.getSession())
+ yield self.app_test_client.delete_mail(mail.mail_id)
inbox_mails = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertEquals(0, len(inbox_mails))
@@ -39,8 +37,7 @@ class DeleteMailTest(SoledadTestBase):
@defer.inlineCallbacks
def test_delete_mail_when_trashing_mail_from_trash_mailbox(self):
mails = yield self.app_test_client.add_multiple_to_mailbox(1, 'trash')
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- yield self.app_test_client.delete_mails([mails[0].ident], session=first_request.getSession())
+ yield self.app_test_client.delete_mails([mails[0].ident])
trash_mails = yield self.app_test_client.get_mails_by_tag('trash')
@@ -52,8 +49,7 @@ class DeleteMailTest(SoledadTestBase):
mails = yield self.app_test_client.add_multiple_to_mailbox(5, 'inbox')
mail_idents = [m.ident for m in mails]
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- yield self.app_test_client.delete_mails(mail_idents, session=first_request.getSession())
+ yield self.app_test_client.delete_mails(mail_idents)
inbox = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertEquals(0, len(inbox))
@@ -63,8 +59,7 @@ class DeleteMailTest(SoledadTestBase):
mails = yield self.app_test_client.add_multiple_to_mailbox(5, 'trash')
mail_idents = [m.ident for m in mails]
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- yield self.app_test_client.delete_mails(mail_idents, session=first_request.getSession())
+ yield self.app_test_client.delete_mails(mail_idents)
trash = yield self.app_test_client.get_mails_by_tag('trash')
self.assertEquals(0, len(trash))
diff --git a/service/test/integration/test_drafts.py b/service/test/integration/test_drafts.py
index a9c7b3f7..657cfab1 100644
--- a/service/test/integration/test_drafts.py
+++ b/service/test/integration/test_drafts.py
@@ -17,7 +17,6 @@
from test.support.integration import SoledadTestBase, MailBuilder
from mockito import unstub, when, any
from twisted.internet import defer
-from pixelated.resources import IPixelatedSession
class DraftsTest(SoledadTestBase):
@@ -27,20 +26,17 @@ class DraftsTest(SoledadTestBase):
@defer.inlineCallbacks
def test_post_sends_mail_and_deletes_previous_draft_if_it_exists(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
# act as if sending the mail by SMTP succeeded
sendmail_deferred = defer.Deferred()
when(self.app_test_client.mail_sender).sendmail(any()).thenReturn(sendmail_deferred)
# creates one draft
first_draft = MailBuilder().with_subject('First draft').build_json()
- first_draft_ident = (yield self.app_test_client.put_mail(first_draft, session=session)[0])['ident']
+ first_draft_ident = (yield self.app_test_client.put_mail(first_draft)[0])['ident']
# sends an updated version of the draft
second_draft = MailBuilder().with_subject('Second draft').with_ident(first_draft_ident).build_json()
- deferred_res = self.post_mail(second_draft, session)
+ deferred_res = self.post_mail(second_draft)
sendmail_deferred.callback(None) # SMTP succeeded
@@ -58,15 +54,12 @@ class DraftsTest(SoledadTestBase):
@defer.inlineCallbacks
def test_post_sends_mail_even_when_draft_does_not_exist(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
# act as if sending the mail by SMTP succeeded
sendmail_deferred = defer.Deferred()
when(self.app_test_client.mail_sender).sendmail(any()).thenReturn(sendmail_deferred)
first_draft = MailBuilder().with_subject('First draft').build_json()
- res = self.post_mail(first_draft, session)
+ res = self.post_mail(first_draft)
sendmail_deferred.callback(True)
yield res
@@ -77,32 +70,25 @@ class DraftsTest(SoledadTestBase):
self.assertEquals('First draft', sent_mails[0].subject)
self.assertEquals(0, len(drafts))
- def post_mail(self, data, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- deferred_res, req = self.app_test_client.post('/mails', data, csrf=csrf, session=session)
+ def post_mail(self, data):
+ deferred_res, req = self.app_test_client.post('/mails', data)
return deferred_res
@defer.inlineCallbacks
def test_put_creates_a_draft_if_it_does_not_exist(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
mail = MailBuilder().with_subject('A new draft').build_json()
- yield self.app_test_client.put_mail(mail, session=session)[0]
+ yield self.app_test_client.put_mail(mail)[0]
mails = yield self.app_test_client.get_mails_by_tag('drafts')
self.assertEquals('A new draft', mails[0].subject)
@defer.inlineCallbacks
def test_put_updates_draft_if_it_already_exists(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
draft = MailBuilder().with_subject('First draft').build_json()
- draft_ident = (yield self.app_test_client.put_mail(draft, session=session)[0])['ident']
+ draft_ident = (yield self.app_test_client.put_mail(draft)[0])['ident']
updated_draft = MailBuilder().with_subject('First draft edited').with_ident(draft_ident).build_json()
- yield self.app_test_client.put_mail(updated_draft, session=session)[0]
+ yield self.app_test_client.put_mail(updated_draft)[0]
drafts = yield self.app_test_client.get_mails_by_tag('drafts')
diff --git a/service/test/integration/test_feedback_service.py b/service/test/integration/test_feedback_service.py
index ff659396..c50c1883 100644
--- a/service/test/integration/test_feedback_service.py
+++ b/service/test/integration/test_feedback_service.py
@@ -1,4 +1,4 @@
-from twisted.trial import unittest
+import unittest
from httmock import urlmatch, HTTMock
from mockito import when
from twisted.internet import defer
diff --git a/service/test/integration/test_logout.py b/service/test/integration/test_logout.py
index 92c2afe5..c9d39d17 100644
--- a/service/test/integration/test_logout.py
+++ b/service/test/integration/test_logout.py
@@ -29,8 +29,7 @@ class MultiUserLogoutTest(MultiUserSoledadTestBase):
@defer.inlineCallbacks
def test_logout_deletes_services_stop_background_reactor_tasks_and_closes_soledad(self):
- response, first_request = yield self.app_test_client.get('/login', as_json=False)
- response, login_request = yield self.app_test_client.login(session=first_request.getSession())
+ response, login_request = yield self.app_test_client.login()
yield response
yield self.wait_for_session_user_id_to_finish()
@@ -38,8 +37,7 @@ class MultiUserLogoutTest(MultiUserSoledadTestBase):
response, request = self.app_test_client.post(
"/logout",
json.dumps({'csrftoken': [login_request.getCookie('XSRF-TOKEN')]}),
- ajax=False,
- session=login_request.getSession(),
+ from_request=login_request,
as_json=False)
yield response
diff --git a/service/test/integration/test_mark_as_read_unread.py b/service/test/integration/test_mark_as_read_unread.py
index c01deefc..18c3ddc2 100644
--- a/service/test/integration/test_mark_as_read_unread.py
+++ b/service/test/integration/test_mark_as_read_unread.py
@@ -30,40 +30,32 @@ class MarkAsReadUnreadTest(SoledadTestBase):
mails = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertNotIn('read', mails[0].status)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- yield self.app_test_client.mark_many_as_read([mail.ident], session)
+ yield self.app_test_client.mark_many_as_read([mail.ident])
mails = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertIn('read', mails[0].status)
@defer.inlineCallbacks
def test_mark_single_as_unread(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
input_mail = MailBuilder().build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- yield self.app_test_client.mark_many_as_read([mail.ident], session)
+ yield self.app_test_client.mark_many_as_read([mail.ident])
- yield self.app_test_client.mark_many_as_unread([mail.ident], session)
+ yield self.app_test_client.mark_many_as_unread([mail.ident])
result = (yield self.app_test_client.get_mails_by_tag('inbox'))[0]
self.assertNotIn('read', result.status)
@defer.inlineCallbacks
def test_mark_many_mails_as_unread(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
input_mail = MailBuilder().with_status([Status.SEEN]).build_input_mail()
input_mail2 = MailBuilder().with_status([Status.SEEN]).build_input_mail()
mail1 = yield self.app_test_client.add_mail_to_inbox(input_mail)
mail2 = yield self.app_test_client.add_mail_to_inbox(input_mail2)
- yield self.app_test_client.mark_many_as_read([mail1.ident, mail2.ident], session)
+ yield self.app_test_client.mark_many_as_read([mail1.ident, mail2.ident])
- yield self.app_test_client.mark_many_as_unread([mail1.ident, mail2.ident], session)
+ yield self.app_test_client.mark_many_as_unread([mail1.ident, mail2.ident])
mails = yield self.app_test_client.get_mails_by_tag('inbox')
@@ -83,9 +75,7 @@ class MarkAsReadUnreadTest(SoledadTestBase):
self.assertNotIn('read', mails[0].status)
self.assertNotIn('read', mails[1].status)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- yield self.app_test_client.mark_many_as_read([mails[0].ident, mails[1].ident], session)
+ yield self.app_test_client.mark_many_as_read([mails[0].ident, mails[1].ident])
mails = yield self.app_test_client.get_mails_by_tag('inbox')
@@ -94,15 +84,12 @@ class MarkAsReadUnreadTest(SoledadTestBase):
@defer.inlineCallbacks
def test_mark_mixed_status_as_read(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
input_mail = MailBuilder().with_subject('first').build_input_mail()
input_mail2 = MailBuilder().with_subject('second').build_input_mail()
yield self.app_test_client.add_mail_to_inbox(input_mail)
mail2 = yield self.app_test_client.add_mail_to_inbox(input_mail2)
- yield self.app_test_client.mark_many_as_read([mail2.ident], session)
+ yield self.app_test_client.mark_many_as_read([mail2.ident])
mails = yield self.app_test_client.get_mails_by_tag('inbox')
@@ -111,7 +98,7 @@ class MarkAsReadUnreadTest(SoledadTestBase):
self.assertEquals(1, len(unread_mails))
self.assertEquals(1, len(read_mails))
- yield self.app_test_client.mark_many_as_read([mails[0].ident, mails[1].ident], session)
+ yield self.app_test_client.mark_many_as_read([mails[0].ident, mails[1].ident])
mails = yield self.app_test_client.get_mails_by_tag('inbox')
diff --git a/service/test/integration/test_multi_user_login.py b/service/test/integration/test_multi_user_login.py
index 2008b320..fe456583 100644
--- a/service/test/integration/test_multi_user_login.py
+++ b/service/test/integration/test_multi_user_login.py
@@ -33,14 +33,13 @@ class MultiUserLoginTest(MultiUserSoledadTestBase):
@defer.inlineCallbacks
def test_logged_in_users_sees_resources(self):
- response, first_request = yield self.app_test_client.get('/login', as_json=False)
- response, login_request = yield self.app_test_client.login(session=first_request.getSession())
+ response, login_request = yield self.app_test_client.login()
yield response
mail = load_mail_from_file('mbox00000000')
mail_id = yield self._create_mail_in_soledad(mail)
expected_mail_dict = {'body': u'Dignissimos ducimus veritatis. Est tenetur consequatur quia occaecati. Vel sit sit voluptas.\n\nEarum distinctio eos. Accusantium qui sint ut quia assumenda. Facere dignissimos inventore autem sit amet. Pariatur voluptatem sint est.\n\nUt recusandae praesentium aspernatur. Exercitationem amet placeat deserunt quae consequatur eum. Unde doloremque suscipit quia.\n\n', 'header': {u'date': u'Tue, 21 Apr 2015 08:43:27 +0000 (UTC)', u'to': [u'carmel@murazikortiz.name'], u'x-tw-pixelated-tags': u'nite, macro, trash', u'from': u'darby.senger@zemlak.biz', u'subject': u'Itaque consequatur repellendus provident sunt quia.'}, 'ident': mail_id, 'status': [], 'tags': [], 'textPlainBody': u'Dignissimos ducimus veritatis. Est tenetur consequatur quia occaecati. Vel sit sit voluptas.\n\nEarum distinctio eos. Accusantium qui sint ut quia assumenda. Facere dignissimos inventore autem sit amet. Pariatur voluptatem sint est.\n\nUt recusandae praesentium aspernatur. Exercitationem amet placeat deserunt quae consequatur eum. Unde doloremque suscipit quia.\n\n', 'mailbox': u'inbox', 'attachments': [], 'security_casing': {'imprints': [{'state': 'no_signature_information'}], 'locks': []}}
- response, request = self.app_test_client.get("/mail/%s" % mail_id, session=login_request.getSession())
+ response, request = self.app_test_client.get("/mail/%s" % mail_id, from_request=login_request)
response = yield response
self.assertEqual(200, request.code)
@@ -49,8 +48,7 @@ class MultiUserLoginTest(MultiUserSoledadTestBase):
@defer.inlineCallbacks
def test_wrong_credentials_cannot_access_resources(self):
- response, first_request = yield self.app_test_client.get('/login', as_json=False)
- response, login_request = self.app_test_client.login('username', 'wrong_password', session=first_request.getSession())
+ response, login_request = self.app_test_client.login('username', 'wrong_password')
response_str = yield response
self.assertEqual(401, login_request.responseCode)
self.assertIn('Invalid username or password', login_request.written)
diff --git a/service/test/integration/test_retrieve_attachment.py b/service/test/integration/test_retrieve_attachment.py
index ac6e52e7..b46d40d5 100644
--- a/service/test/integration/test_retrieve_attachment.py
+++ b/service/test/integration/test_retrieve_attachment.py
@@ -86,9 +86,7 @@ class RetrieveAttachmentTest(SoledadTestBase):
datagen, headers = multipart_encode([file])
post_data = "".join(datagen)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- _, req = yield self.app_test_client.post_attachment(post_data, headers, session)
+ _, req = yield self.app_test_client.post_attachment(post_data, headers)
self.assertEqual(201, req.code)
self.assertEqual('/attachment/B5B4ED80AC3B894523D72E375DACAA2FC6606C18EDF680FE95903086C8B5E14A', req.responseHeaders.getRawHeaders('location')[0])
diff --git a/service/test/integration/test_static_files.py b/service/test/integration/test_static_files.py
deleted file mode 100644
index e3fa8af5..00000000
--- a/service/test/integration/test_static_files.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#
-# Copyright (c) 2016 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-
-
-from twisted.internet.defer import inlineCallbacks
-from test.support.integration import SoledadTestBase
-
-
-class StaticFilesTest(SoledadTestBase):
-
- @inlineCallbacks
- def test_should_find_static_file(self):
- _, request = yield self.app_test_client.get('/static/js/main.js', as_json=False, ajax=False)
- self.assertEqual(200, request.responseCode)
diff --git a/service/test/integration/test_tags.py b/service/test/integration/test_tags.py
index d107e320..555a7382 100644
--- a/service/test/integration/test_tags.py
+++ b/service/test/integration/test_tags.py
@@ -31,9 +31,7 @@ class TagsTest(SoledadTestBase):
input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- yield self.app_test_client.post_tags(mail.ident, self._tags_json(['IMPORTANT']), session)
+ yield self.app_test_client.post_tags(mail.ident, self._tags_json(['IMPORTANT']))
mails = yield self.app_test_client.get_mails_by_tag('inbox')
self.assertEquals({'IMPORTANT'}, set(mails[0].tags))
@@ -43,18 +41,15 @@ class TagsTest(SoledadTestBase):
@defer.inlineCallbacks
def test_use_old_casing_when_same_tag_with_different_casing_is_posted(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
-
input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- yield self.app_test_client.post_tags(mail.ident, self._tags_json(['ImPoRtAnT']), session)
+ yield self.app_test_client.post_tags(mail.ident, self._tags_json(['ImPoRtAnT']))
mails = yield self.app_test_client.get_mails_by_tag('ImPoRtAnT')
self.assertEquals({'ImPoRtAnT'}, set(mails[0].tags))
another_input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
another_mail = yield self.app_test_client.add_mail_to_inbox(another_input_mail)
- yield self.app_test_client.post_tags(another_mail.ident, self._tags_json(['IMPORTANT']), session)
+ yield self.app_test_client.post_tags(another_mail.ident, self._tags_json(['IMPORTANT']))
mails = yield self.app_test_client.get_mails_by_tag('IMPORTANT')
self.assertEquals(0, len(mails))
mails = yield self.app_test_client.get_mails_by_tag('ImPoRtAnT')
@@ -67,9 +62,7 @@ class TagsTest(SoledadTestBase):
input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- yield self.app_test_client.post_tags(mail.ident, self._tags_json(['ImPoRtAnT']), session)
+ yield self.app_test_client.post_tags(mail.ident, self._tags_json(['ImPoRtAnT']))
mails = yield self.app_test_client.get_mails_by_tag('important')
self.assertEquals(0, len(mails))
@@ -85,9 +78,7 @@ class TagsTest(SoledadTestBase):
input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
- yield self.app_test_client.post_tags(mail.ident, self._tags_json(['tag1', ' ']), session)
+ yield self.app_test_client.post_tags(mail.ident, self._tags_json(['tag1', ' ']))
mail = yield self.app_test_client.get_mail(mail.ident)
@@ -98,10 +89,8 @@ class TagsTest(SoledadTestBase):
input_mail = MailBuilder().with_subject('Mail with tags').build_input_mail()
mail = yield self.app_test_client.add_mail_to_inbox(input_mail)
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- session = first_request.getSession()
for tag in SPECIAL_TAGS:
- response = yield self.app_test_client.post_tags(mail.ident, self._tags_json([tag.name.upper()]), session)
+ response = yield self.app_test_client.post_tags(mail.ident, self._tags_json([tag.name.upper()]))
self.assertEquals("None of the following words can be used as tags: %s" % tag.name, response)
mail = yield self.app_test_client.mail_store.get_mail(mail.ident)
diff --git a/service/test/integration/test_users_count.py b/service/test/integration/test_users_count.py
index a9813b2c..a03adacf 100644
--- a/service/test/integration/test_users_count.py
+++ b/service/test/integration/test_users_count.py
@@ -31,8 +31,7 @@ class UsersResourceTest(MultiUserSoledadTestBase):
@defer.inlineCallbacks
def test_online_users_count_uses_leap_auth_privileges(self):
- response, first_request = yield self.app_test_client.get('/', as_json=False)
- response, login_request = yield self.app_test_client.login(session=first_request.getSession())
+ response, login_request = yield self.app_test_client.login()
yield response
yield self.wait_for_session_user_id_to_finish()
@@ -41,7 +40,7 @@ class UsersResourceTest(MultiUserSoledadTestBase):
response, request = self.app_test_client.get(
"/users",
json.dumps({'csrftoken': [login_request.getCookie('XSRF-TOKEN')]}),
- session=login_request.getSession(),
+ from_request=login_request,
as_json=False)
yield response
diff --git a/service/test/support/integration/app_test_client.py b/service/test/support/integration/app_test_client.py
index fa695708..d52c85c0 100644
--- a/service/test/support/integration/app_test_client.py
+++ b/service/test/support/integration/app_test_client.py
@@ -38,7 +38,7 @@ from leap.soledad.client import Soledad
from leap.bitmask.mail.adaptors.soledad import SoledadMailAdaptor
from pixelated.adapter.mailstore.leap_attachment_store import LeapAttachmentStore
from pixelated.adapter.services.feedback_service import FeedbackService
-from pixelated.application import UserAgentMode, set_up_protected_resources, get_static_folder
+from pixelated.application import UserAgentMode, set_up_protected_resources
from pixelated.config.sessions import LeapSession
from pixelated.config.services import Services, ServicesFactory, SingleUserServicesFactory
from pixelated.config.site import PixelatedSite
@@ -49,7 +49,6 @@ from pixelated.adapter.search import SearchEngine
from pixelated.adapter.services.draft_service import DraftService
from pixelated.adapter.services.mail_service import MailService
from pixelated.resources.root_resource import RootResource
-from pixelated.resources.session import IPixelatedSession
from test.support.integration.model import MailBuilder
from test.support.test_helper import request_mock
from test.support.integration.model import ResponseMail
@@ -218,7 +217,7 @@ class AppTestClient(object):
services = self._test_account.services
self.service_factory.add_session('someuserid', services)
- self.resource = RootResource(self.service_factory, get_static_folder())
+ self.resource = RootResource(self.service_factory)
provider = mock()
self.resource.initialize(provider)
else:
@@ -227,7 +226,7 @@ class AppTestClient(object):
bonafide_checker = StubAuthenticator(provider)
bonafide_checker.add_user('username', 'password')
- self.resource = set_up_protected_resources(RootResource(self.service_factory, get_static_folder()), provider, self.service_factory, authenticator=bonafide_checker)
+ self.resource = set_up_protected_resources(RootResource(self.service_factory), provider, self.service_factory, authenticator=bonafide_checker)
@defer.inlineCallbacks
def create_user(self, account_name):
@@ -279,23 +278,17 @@ class AppTestClient(object):
request.args = get_args
return self._render(request, as_json)
- def post(self, path, body='', headers=None, ajax=True, csrf='token', session=None):
+ def post(self, path, body='', headers=None, ajax=True, csrf='token'):
headers = headers or {'Content-Type': 'application/json'}
request = request_mock(path=path, method="POST", body=body, headers=headers, ajax=ajax, csrf=csrf)
- if session:
- request.session = session
return self._render(request)
- def put(self, path, body, ajax=True, csrf='token', session=None):
+ def put(self, path, body, ajax=True, csrf='token'):
request = request_mock(path=path, method="PUT", body=body, headers={'Content-Type': ['application/json']}, ajax=ajax, csrf=csrf)
- if session:
- request.session = session
return self._render(request)
- def delete(self, path, body="", ajax=True, csrf='token', session=None):
+ def delete(self, path, body="", ajax=True, csrf='token'):
request = request_mock(path=path, body=body, headers={'Content-Type': ['application/json']}, method="DELETE", ajax=ajax, csrf=csrf)
- if session:
- request.session = session
return self._render(request)
@defer.inlineCallbacks
@@ -306,6 +299,7 @@ class AppTestClient(object):
def account_for(self, username):
return self.accounts[username]
+ # TODO: remove
def add_mail_to_user_inbox(self, input_mail, username):
return self.account_for(username).mail_store.add_mail('INBOX', input_mail.raw)
@@ -334,6 +328,10 @@ class AppTestClient(object):
mail_sender.sendmail.side_effect = lambda mail: succeed(mail)
return mail_sender
+ # TODO: remove
+ def _generate_soledad_test_folder_name(self, soledad_test_folder='/tmp/soledad-test/test'):
+ return os.path.join(soledad_test_folder, str(uuid.uuid4()))
+
def get_mails_by_tag(self, tag, page=1, window=100):
tags = 'tag:%s' % tag
return self.search(tags, page, window)
@@ -348,6 +346,13 @@ class AppTestClient(object):
res = yield res
defer.returnValue([ResponseMail(m) for m in res['mails']])
+ # TODO: remove
+ @defer.inlineCallbacks
+ def get_mails_by_mailbox_name(self, mbox_name):
+ mail_ids = yield self.mail_store.get_mailbox_mail_ids(mbox_name)
+ mails = yield self.mail_store.get_mails(mail_ids)
+ defer.returnValue(mails)
+
@defer.inlineCallbacks
def get_attachment(self, ident, encoding, filename=None, content_type=None, ajax=True, csrf='token'):
params = {'encoding': [encoding]}
@@ -360,20 +365,17 @@ class AppTestClient(object):
defer.returnValue((res, req))
@defer.inlineCallbacks
- def post_attachment(self, data, headers, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- deferred_result, req = self.post('/attachment', body=data, headers=headers, csrf=csrf, session=session)
+ def post_attachment(self, data, headers):
+ deferred_result, req = self.post('/attachment', body=data, headers=headers)
res = yield deferred_result
defer.returnValue((res, req))
- def put_mail(self, data, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.put('/mails', data, csrf=csrf, session=session)
+ def put_mail(self, data):
+ res, req = self.put('/mails', data)
return res, req
- def post_tags(self, mail_ident, tags_json, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.post("/mail/%s/tags" % mail_ident, tags_json, csrf=csrf, session=session)
+ def post_tags(self, mail_ident, tags_json):
+ res, req = self.post("/mail/%s/tags" % mail_ident, tags_json)
return res
def get_tags(self, **kwargs):
@@ -384,24 +386,21 @@ class AppTestClient(object):
res, req = self.get('/mail/%s' % mail_ident)
return res
- def delete_mail(self, mail_ident, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.delete("/mail/%s" % mail_ident, csrf=csrf, session=session)
+ # TODO: remove
+ def delete_mail(self, mail_ident):
+ res, req = self.delete("/mail/%s" % mail_ident)
return res
- def delete_mails(self, idents, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.post("/mails/delete", json.dumps({'idents': idents}), csrf=csrf, session=session)
+ def delete_mails(self, idents):
+ res, req = self.post("/mails/delete", json.dumps({'idents': idents}))
return res
- def mark_many_as_unread(self, idents, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.post('/mails/unread', json.dumps({'idents': idents}), csrf=csrf, session=session)
+ def mark_many_as_unread(self, idents):
+ res, req = self.post('/mails/unread', json.dumps({'idents': idents}))
return res
- def mark_many_as_read(self, idents, session):
- csrf = IPixelatedSession(session).get_csrf_token()
- res, req = self.post('/mails/read', json.dumps({'idents': idents}), csrf=csrf, session=session)
+ def mark_many_as_read(self, idents):
+ res, req = self.post('/mails/read', json.dumps({'idents': idents}))
return res
def get_contacts(self, query):
diff --git a/service/test/support/integration/multi_user_client.py b/service/test/support/integration/multi_user_client.py
index de272e16..82acb210 100644
--- a/service/test/support/integration/multi_user_client.py
+++ b/service/test/support/integration/multi_user_client.py
@@ -19,12 +19,11 @@ from mockito import mock, when, any as ANY
from pixelated.authentication import Authenticator, Authentication
from twisted.internet import defer
-from pixelated.application import UserAgentMode, set_up_protected_resources, get_static_folder
+from pixelated.application import UserAgentMode, set_up_protected_resources
from pixelated.config.services import ServicesFactory
from pixelated.config.sessions import LeapSessionFactory
import pixelated.config.services
-from pixelated.resources import IPixelatedSession
from pixelated.resources.root_resource import RootResource
from test.support.integration import AppTestClient
from test.support.integration.app_test_client import AppTestAccount, StubSRPChecker
@@ -46,7 +45,7 @@ class MultiUserClient(AppTestClient):
self.service_factory = ServicesFactory(UserAgentMode(is_single_user=False))
- root_resource = RootResource(self.service_factory, get_static_folder())
+ root_resource = RootResource(self.service_factory)
leap_provider = mock()
self.credentials_checker = StubSRPChecker(leap_provider)
self.resource = set_up_protected_resources(root_resource, leap_provider, self.service_factory)
@@ -58,41 +57,41 @@ class MultiUserClient(AppTestClient):
else:
when(Authenticator)._bonafide_auth(username, password).thenRaise(SRPAuthError)
- def login(self, username='username', password='password', session=None):
- auth_session = Authentication(username, 'some_user_token', 'some_user_uuid', 'session_id', {'is_admin': False})
+ def login(self, username='username', password='password'):
+ session = Authentication(username, 'some_user_token', 'some_user_uuid', 'session_id', {'is_admin': False})
leap_session = self._test_account.leap_session
- leap_session.user_auth = auth_session
+ leap_session.user_auth = session
config = mock()
config.leap_home = 'some_folder'
leap_session.config = config
leap_session.fresh_account = False
self.leap_session = leap_session
self.services = self._test_account.services
- self.user_auth = auth_session
+ self.user_auth = session
self._mock_bonafide_auth(username, password)
- when(LeapSessionFactory).create(username, password, auth_session).thenReturn(leap_session)
+ when(LeapSessionFactory).create(username, password, session).thenReturn(leap_session)
with patch('mockito.invocation.AnswerSelector', AnswerSelector):
when(leap_session).initial_sync().thenAnswer(lambda: defer.succeed(None))
when(pixelated.config.services).Services(ANY()).thenReturn(self.services)
- csrftoken = IPixelatedSession(session).get_csrf_token()
- request = request_mock(path='/login', method="POST", body={'username': username, 'password': password, 'csrftoken': csrftoken}, ajax=False)
- request.session = session
+ request = request_mock(path='/login', method="POST", body={'username': username, 'password': password})
return self._render(request, as_json=False)
- def get(self, path, get_args='', as_json=True, session=None):
+ def get(self, path, get_args='', as_json=True, from_request=None):
request = request_mock(path)
request.args = get_args
- if session:
+ if from_request:
+ session = from_request.getSession()
request.session = session
return self._render(request, as_json)
- def post(self, path, body='', headers=None, ajax=True, csrf='token', as_json=True, session=None):
+ def post(self, path, body='', headers=None, ajax=True, csrf='token', as_json=True, from_request=None):
headers = headers or {'Content-Type': 'application/json'}
request = request_mock(path=path, method="POST", body=body, headers=headers, ajax=ajax, csrf=csrf)
- if session:
+ if from_request:
+ session = from_request.getSession()
request.session = session
return self._render(request, as_json)
diff --git a/service/test/unit/resources/test_auth.py b/service/test/unit/resources/test_auth.py
deleted file mode 100644
index 3dc3e29f..00000000
--- a/service/test/unit/resources/test_auth.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from mockito import mock, when, any as ANY
-
-from pixelated.application import get_static_folder
-from pixelated.resources.auth import SessionChecker, PixelatedRealm, PixelatedAuthSessionWrapper
-from pixelated.resources.login_resource import LoginResource
-from pixelated.resources.root_resource import RootResource
-from test.unit.resources import DummySite
-from twisted.cred import error
-from twisted.cred.checkers import ANONYMOUS, AllowAnonymousAccess
-from twisted.cred.portal import Portal
-from twisted.internet.defer import succeed, fail
-from twisted.python import failure
-from twisted.trial import unittest
-from twisted.web._auth.wrapper import UnauthorizedResource
-from twisted.web.resource import IResource, getChildForRequest
-from twisted.web.test.requesthelper import DummyRequest
-
-
-class TestPixelatedRealm(unittest.TestCase):
-
- def setUp(self):
- self.authenticated_root_resource = mock()
- self.public_root_resource = mock()
- self.realm = PixelatedRealm(self.authenticated_root_resource, self.public_root_resource)
-
- def test_anonymous_user_gets_anonymous_resource(self):
- interface, avatar, logout_handler = self.realm.requestAvatar(ANONYMOUS, None, IResource)
- self.assertEqual(interface, IResource)
- self.assertIs(avatar, self.public_root_resource)
-
- def test_authenticated_user_gets_root_resource(self):
- interface, avatar, logout_handler = self.realm.requestAvatar('username', None, IResource)
- self.assertEqual(interface, IResource)
- self.assertIs(avatar, self.authenticated_root_resource)
-
-
-class TestPixelatedAuthSessionWrapper(unittest.TestCase):
-
- def setUp(self):
- self.realm_mock = mock()
- services_factory = mock()
- session_checker = SessionChecker(services_factory)
- self.portal = Portal(self.realm_mock, [session_checker, AllowAnonymousAccess()])
- self.user_uuid_mock = mock()
- self.root_resource = RootResource(services_factory, get_static_folder())
- self.anonymous_resource = RootResource(services_factory, get_static_folder(), public=True)
-
- self.session_wrapper = PixelatedAuthSessionWrapper(self.portal)
- self.request = DummyRequest([])
- self.request.prepath = ['']
- self.request.path = '/'
-
- def test_root_url_should_delegate_to_public_root_resource_for_unauthenticated_user(self):
- when(self.realm_mock).requestAvatar(ANONYMOUS, None, IResource).thenReturn((IResource, self.anonymous_resource, lambda: None))
- request = DummyRequest([''])
- deferred_resource = getChildForRequest(self.session_wrapper, request)
- d = deferred_resource.d
-
- def assert_public_root_resource(resource):
- self.assertIs(resource, self.anonymous_resource)
-
- return d.addCallback(assert_public_root_resource)
-
- def test_root_url_should_delegate_to_protected_root_resource_for_authenticated_user(self):
- when(self.realm_mock).requestAvatar(ANY(), None, IResource).thenReturn((IResource, self.root_resource, lambda: None))
- request = DummyRequest([''])
- deferred_resource = getChildForRequest(self.session_wrapper, request)
- d = deferred_resource.d
-
- def assert_protected_root_resource(resource):
- self.assertIsInstance(resource, RootResource)
-
- return d.addCallback(assert_protected_root_resource)
diff --git a/service/test/unit/resources/test_inbox_resource.py b/service/test/unit/resources/test_inbox_resource.py
deleted file mode 100644
index 9af355ca..00000000
--- a/service/test/unit/resources/test_inbox_resource.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import re
-
-from mock import MagicMock, patch
-from mockito import mock, when, any as ANY
-
-from pixelated.application import UserAgentMode
-from pixelated.resources.features_resource import FeaturesResource
-from test.unit.resources import DummySite
-from twisted.trial import unittest
-from twisted.web.test.requesthelper import DummyRequest
-from pixelated.resources.inbox_resource import InboxResource, MODE_STARTUP, MODE_RUNNING
-
-
-class TestInboxResource(unittest.TestCase):
- MAIL_ADDRESS = 'test_user@pixelated-project.org'
-
- def setUp(self):
- mail_service = mock()
- mail_service.account_email = self.MAIL_ADDRESS
-
- services = mock()
- services.mail_service = mail_service
-
- services_factory = mock()
- services_factory.mode = mock()
- when(services_factory).services(ANY()).thenReturn(services)
-
- self.inbox_resource = InboxResource(services_factory)
- self.web = DummySite(self.inbox_resource)
-
- def test_render_GET_should_template_account_email(self):
- self.inbox_resource._html_template = "<html><head><title>$account_email</title></head></html>"
- self.inbox_resource.initialize()
-
- request = DummyRequest([''])
- request.addCookie = lambda key, value: 'stubbed'
-
- d = self.web.get(request)
-
- def assert_response(_):
- expected = "<title>{0}</title>".format(self.MAIL_ADDRESS)
- matches = re.findall(expected, request.written[0])
- self.assertEquals(len(matches), 1)
-
- d.addCallback(assert_response)
- return d
diff --git a/service/test/unit/resources/test_login_resource.py b/service/test/unit/resources/test_login_resource.py
index 1161acc4..45036f8d 100644
--- a/service/test/unit/resources/test_login_resource.py
+++ b/service/test/unit/resources/test_login_resource.py
@@ -157,19 +157,6 @@ class TestLoginResource(unittest.TestCase):
d.addCallback(assert_default_invalid_banner_disclaimer_rendered)
return d
- def test_form_should_contain_csrftoken_input(self):
- request = DummyRequest([''])
-
- d = self.web.get(request)
-
- def assert_form_has_csrftoken_input(_):
- input_username = 'name="csrftoken"'
- written_response = ''.join(request.written)
- self.assertIn(input_username, written_response)
-
- d.addCallback(assert_form_has_csrftoken_input)
- return d
-
class TestLoginPOST(unittest.TestCase):
def setUp(self):
@@ -235,7 +222,7 @@ class TestLoginPOST(unittest.TestCase):
def assert_interstitial_in_response(_):
mock_authenticate.assert_called_once_with(self.username, self.password)
- interstitial_js_in_template = '<script src="static/Interstitial.js"></script>'
+ interstitial_js_in_template = '<script src="startup-assets/Interstitial.js"></script>'
self.assertIn(interstitial_js_in_template, self.request.written[0])
d.addCallback(assert_interstitial_in_response)
diff --git a/service/test/unit/resources/test_root_resource.py b/service/test/unit/resources/test_root_resource.py
index 1edba98c..4ff11ce8 100644
--- a/service/test/unit/resources/test_root_resource.py
+++ b/service/test/unit/resources/test_root_resource.py
@@ -1,95 +1,14 @@
-import os
+import unittest
import re
from mock import MagicMock, patch
from mockito import mock, when, any as ANY
-import pixelated
-from pixelated.application import UserAgentMode, get_static_folder
-from pixelated.resources import IPixelatedSession, UnAuthorizedResource
+from pixelated.application import UserAgentMode
from pixelated.resources.features_resource import FeaturesResource
-from pixelated.resources.login_resource import LoginResource
from test.unit.resources import DummySite
-from twisted.cred.checkers import ANONYMOUS
-from twisted.internet.defer import succeed
-from twisted.trial import unittest
-from twisted.web.resource import IResource, getChildForRequest
-from twisted.web.static import File
from twisted.web.test.requesthelper import DummyRequest
-from pixelated.resources.root_resource import InboxResource, RootResource, MODE_STARTUP, MODE_RUNNING
-
-
-class TestPublicRootResource(unittest.TestCase):
-
- def setUp(self):
- self.public_root_resource = RootResource(mock(), get_static_folder(), public=True)
- self.web = DummySite(self.public_root_resource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_put_child_public_adds_resource(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- url_fragment, resource_mock = 'some-url-fragment', mock()
- self.public_root_resource.putChildPublic(url_fragment, resource_mock)
- request = DummyRequest([url_fragment])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.public_root_resource, request)
- self.assertIs(child_resource, resource_mock)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_put_child_protected_adds_unauthorized(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- url_fragment, resource_mock = 'some-url-fragment', mock()
- self.public_root_resource.putChildProtected(url_fragment, resource_mock)
- request = DummyRequest([url_fragment])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.public_root_resource, request)
- self.assertIsInstance(child_resource, UnAuthorizedResource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_put_child_adds_unauthorized(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- url_fragment, resource_mock = 'some-url-fragment', mock()
- self.public_root_resource.putChild(url_fragment, resource_mock)
- request = DummyRequest([url_fragment])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.public_root_resource, request)
- self.assertIsInstance(child_resource, UnAuthorizedResource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_private_resource_returns_401(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- request = DummyRequest(['mails'])
- request.addCookie = MagicMock(return_value='stubbed')
- d = self.web.get(request)
-
- def assert_unauthorized(request):
- self.assertEqual(401, request.responseCode)
- self.assertEqual("Unauthorized!", request.written[0])
-
- d.addCallback(assert_unauthorized)
- return d
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_login_url_should_delegate_to_login_resource(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- request = DummyRequest(['login'])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.public_root_resource, request)
- self.assertIsInstance(child_resource, LoginResource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_root_url_should_redirect_to_login_resource(self, *mocks):
- self.public_root_resource.initialize(provider=mock(), authenticator=mock())
- request = DummyRequest([''])
- request.addCookie = MagicMock(return_value='stubbed')
- d = self.web.get(request)
-
- def assert_redirect(request):
- self.assertEqual(302, request.responseCode)
- self.assertEqual(["login"], request.responseHeaders.getRawHeaders('location', [None]))
-
- d.addCallback(assert_redirect)
- return d
+from pixelated.resources.root_resource import RootResource, MODE_STARTUP, MODE_RUNNING
class TestRootResource(unittest.TestCase):
@@ -105,46 +24,29 @@ class TestRootResource(unittest.TestCase):
when(self.services_factory).services(ANY()).thenReturn(self.services)
self.mail_service.account_email = self.MAIL_ADDRESS
- self.root_resource = RootResource(self.services_factory, get_static_folder())
- self.web = DummySite(self.root_resource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_put_child_protected_adds_resource(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
- url_fragment, resource_mock = 'some-url-fragment', mock()
- self.root_resource.putChildProtected(url_fragment, resource_mock)
- request = DummyRequest([url_fragment])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.root_resource, request)
- self.assertIs(child_resource, resource_mock)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_put_child_adds_resource(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
- url_fragment, resource_mock = 'some-url-fragment', mock()
- self.root_resource.putChild(url_fragment, resource_mock)
- request = DummyRequest([url_fragment])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.root_resource, request)
- self.assertIs(child_resource, resource_mock)
-
- def test_root_url_should_delegate_to_inbox(self):
+ root_resource = RootResource(self.services_factory)
+ root_resource._html_template = "<html><head><title>$account_email</title></head></html>"
+ root_resource._mode = root_resource
+ self.web = DummySite(root_resource)
+ self.root_resource = root_resource
+
+ def test_render_GET_should_template_account_email(self):
request = DummyRequest([''])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.root_resource, request)
- self.assertIsInstance(child_resource, InboxResource)
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_login_url_should_delegate_to_login_resource(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
- request = DummyRequest(['login'])
- request.addCookie = MagicMock(return_value='stubbed')
- child_resource = getChildForRequest(self.root_resource, request)
- self.assertIsInstance(child_resource, LoginResource)
+ request.addCookie = lambda key, value: 'stubbed'
+
+ d = self.web.get(request)
+
+ def assert_response(_):
+ expected = "<title>{0}</title>".format(self.MAIL_ADDRESS)
+ matches = re.findall(expected, request.written[0])
+ self.assertEquals(len(matches), 1)
+
+ d.addCallback(assert_response)
+ return d
def _test_should_renew_xsrf_cookie(self):
request = DummyRequest([''])
- request.addCookie = MagicMock(return_value='stubbed')
+ request.addCookie = MagicMock()
generated_csrf_token = 'csrf_token'
mock_sha = MagicMock()
mock_sha.hexdigest = MagicMock(return_value=generated_csrf_token)
@@ -170,7 +72,6 @@ class TestRootResource(unittest.TestCase):
self.root_resource._mode = MODE_STARTUP
request = DummyRequest(['/child'])
- request.addCookie = MagicMock(return_value='stubbed')
request.getCookie = MagicMock(return_value='irrelevant -- stubbed')
d = self.web.get(request)
@@ -186,12 +87,8 @@ class TestRootResource(unittest.TestCase):
request.requestHeaders.setRawHeaders('x-requested-with', ['XMLHttpRequest'])
request.requestHeaders.setRawHeaders('x-xsrf-token', [csrf_token])
- @patch('pixelated.resources.mails_resource.events.register')
- def test_should_unauthorize_child_resource_ajax_requests_when_csrf_mismatch(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
+ def test_should_unauthorize_child_resource_ajax_requests_when_csrf_mismatch(self):
request = DummyRequest(['/child'])
- request.addCookie = MagicMock(return_value='stubbed')
request.method = 'POST'
self._mock_ajax_csrf(request, 'stubbed csrf token')
@@ -206,46 +103,11 @@ class TestRootResource(unittest.TestCase):
d.addCallback(assert_unauthorized)
return d
- def test_GET_should_return_503_for_uninitialized_resource(self):
- request = DummyRequest(['/sandbox/'])
- request.addCookie = MagicMock(return_value='stubbed')
- request.method = 'GET'
-
- request.getCookie = MagicMock(return_value='stubbed csrf token')
-
- d = self.web.get(request)
-
- def assert_unavailable(_):
- self.assertEqual(503, request.responseCode)
-
- d.addCallback(assert_unavailable)
- return d
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_GET_should_return_404_for_non_existing_resource(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
- request = DummyRequest(['non-existing-child'])
- request.addCookie = MagicMock(return_value='stubbed')
- request.method = 'GET'
- request.getCookie = MagicMock(return_value='stubbed csrf token')
-
- d = self.web.get(request)
-
- def assert_not_found(_):
- self.assertEqual(404, request.responseCode)
-
- d.addCallback(assert_not_found)
- return d
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_should_404_non_existing_resource_with_valid_csrf(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
- request = DummyRequest(['non-existing-child'])
- request.addCookie = MagicMock(return_value='stubbed')
+ def test_should_404_non_existing_resource_with_valid_csrf(self):
+ request = DummyRequest(['/non-existing-child'])
request.method = 'POST'
self._mock_ajax_csrf(request, 'stubbed csrf token')
+
request.getCookie = MagicMock(return_value='stubbed csrf token')
d = self.web.get(request)
@@ -259,10 +121,9 @@ class TestRootResource(unittest.TestCase):
def test_should_authorize_child_resource_non_ajax_GET_requests(self):
request = DummyRequest(['features'])
- request.addCookie = MagicMock(return_value='stubbed')
request.getCookie = MagicMock(return_value='irrelevant -- stubbed')
- self.root_resource.putChild('features', FeaturesResource())
+ self.root_resource._child_resources.add('features', FeaturesResource())
self.root_resource._mode = MODE_RUNNING
d = self.web.get(request)
@@ -273,10 +134,7 @@ class TestRootResource(unittest.TestCase):
d.addCallback(assert_unauthorized)
return d
- @patch('pixelated.resources.mails_resource.events.register')
- def test_should_unauthorize_child_resource_non_ajax_POST_requests_when_csrf_input_mismatch(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
+ def test_should_unauthorize_child_resource_non_ajax_POST_requests_when_csrf_input_mismatch(self):
request = DummyRequest(['mails'])
request.method = 'POST'
request.addArg('csrftoken', 'some csrf token')
@@ -284,7 +142,6 @@ class TestRootResource(unittest.TestCase):
mock_content.read = MagicMock(return_value={})
request.content = mock_content
- request.addCookie = MagicMock(return_value='stubbed')
request.getCookie = MagicMock(return_value='mismatched csrf token')
d = self.web.get(request)
@@ -295,62 +152,3 @@ class TestRootResource(unittest.TestCase):
d.addCallback(assert_unauthorized)
return d
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_assets_should_be_publicly_available(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
- request = DummyRequest(['static', 'dummy.json'])
- request.addCookie = MagicMock(return_value='stubbed')
- d = self.web.get(request)
-
- def assert_response(_):
- self.assertEqual(200, request.responseCode)
-
- d.addCallback(assert_response)
- return d
-
- @patch('pixelated.resources.mails_resource.events.register')
- def test_login_should_be_publicly_available(self, *mocks):
- self.root_resource.initialize(provider=mock(), authenticator=mock())
-
- request = DummyRequest(['login'])
- request.addCookie = MagicMock(return_value='stubbed')
- d = self.web.get(request)
-
- def assert_response(_):
- self.assertEqual(200, request.responseCode)
-
- d.addCallback(assert_response)
- return d
-
- def test_root_should_be_handled_by_inbox_resource(self):
- request = DummyRequest([])
- request.addCookie = MagicMock(return_value='stubbed')
- request.prepath = ['']
- request.path = '/'
-
- resource = self.root_resource.getChildWithDefault(request.prepath[-1], request)
- self.assertIsInstance(resource, InboxResource)
-
- def test_inbox_should_not_be_public(self):
- request = DummyRequest([])
- request.addCookie = MagicMock(return_value='stubbed')
- request.prepath = ['']
- request.path = '/'
-
- resource = self.root_resource.getChildWithDefault(request.prepath[-1], request)
- self.assertIsInstance(resource, InboxResource)
-
- def test_every_url_should_get_csrftoken_header(self):
- # self.root_resource.initialize(provider=mock(), authenticator=mock())
- request = DummyRequest(['any'])
- request.addCookie = MagicMock(return_value='stubbed')
- d = self.web.get(request)
-
- def assert_add_cookie_called_for_csrftoken(request):
- csrftoken = IPixelatedSession(request.getSession()).get_csrf_token()
- self.assertEqual([(('XSRF-TOKEN', csrftoken),)], request.addCookie.call_args_list)
-
- d.addCallback(assert_add_cookie_called_for_csrftoken)
- return d
diff --git a/service/test/unit/resources/test_session.py b/service/test/unit/resources/test_session.py
deleted file mode 100644
index fe47483d..00000000
--- a/service/test/unit/resources/test_session.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from twisted.trial import unittest
-from mockito import mock
-from pixelated.resources.session import CSRF_TOKEN_LENGTH, PixelatedSession
-
-
-class TestPixelatedSession(unittest.TestCase):
-
- def setUp(self):
- self.pixelated_session = PixelatedSession(mock())
-
- def test_csrf_token_should_be_configured_length(self):
- self.assertEqual(len(self.pixelated_session.get_csrf_token()), 2 * CSRF_TOKEN_LENGTH)
-
- def test_csrf_token_should_be_hexdigested(self):
- self.assertTrue(all(c in '0123456789abcdef' for c in self.pixelated_session.get_csrf_token()))
-
- def test_csrf_token_should_always_be_the_same_for_one_session(self):
- first_csrf_token = self.pixelated_session.get_csrf_token()
- second_csrf_token = self.pixelated_session.get_csrf_token()
- self.assertEqual(first_csrf_token, second_csrf_token)
-
- def test_csrf_token_should_be_different_for_different_session(self):
- first_csrf_token = self.pixelated_session.get_csrf_token()
- second_csrf_token = PixelatedSession(mock()).get_csrf_token()
- self.assertNotEqual(first_csrf_token, second_csrf_token)
diff --git a/service/test/unit/test_welcome_mail.py b/service/test/unit/test_welcome_mail.py
index 42e21e8d..7eb65903 100644
--- a/service/test/unit/test_welcome_mail.py
+++ b/service/test/unit/test_welcome_mail.py
@@ -41,7 +41,8 @@ class TestWelcomeMail(unittest.TestCase):
with open(os.path.join(current_path,
'..',
'..',
- 'templates',
+ 'pixelated',
+ 'assets',
'welcome.mail.pt-BR')) as mail_template_file:
mail_template = message_from_file(mail_template_file)
diff --git a/web-ui/.bowerrc b/web-ui/.bowerrc
index d1c592ed..5773025b 100644
--- a/web-ui/.bowerrc
+++ b/web-ui/.bowerrc
@@ -1,3 +1,3 @@
{
- "directory": "public/bower_components"
+ "directory": "app/bower_components"
}
diff --git a/web-ui/.jshintignore b/web-ui/.jshintignore
index f2f274fe..6a32b1a4 100644
--- a/web-ui/.jshintignore
+++ b/web-ui/.jshintignore
@@ -1,8 +1,4 @@
-**/*.min.js
-**/*-min.js
-public/node_modules
-public/bower_components
-public/js/lib
-public/js/generated
-public/signup.js
-src/js/index.js
+app/node_modules
+app/bower_components
+app/js/lib
+app/js/generated
diff --git a/web-ui/.jshintrc b/web-ui/.jshintrc
index 7debbfbe..1e2a147d 100644
--- a/web-ui/.jshintrc
+++ b/web-ui/.jshintrc
@@ -33,7 +33,6 @@
"_",
"Pixelated",
"Handlebars",
- "Bloodhound",
- "Snap"
+ "Bloodhound"
]
}
diff --git a/web-ui/.tx/config b/web-ui/.tx/config
index 04fc6bc2..25299ced 100644
--- a/web-ui/.tx/config
+++ b/web-ui/.tx/config
@@ -2,7 +2,7 @@
host = https://www.transifex.com
[pixelated-user-agent.web-ui]
-file_filter = public/locales/<lang>/translation.json
-source_file = public/locales/en_US/translation.json
+file_filter = app/locales/<lang>/translation.json
+source_file = app/locales/en_US/translation.json
source_lang = en_US
type = KEYVALUEJSON
diff --git a/web-ui/Makefile b/web-ui/Makefile
index efd59c9e..0bc9d5d4 100644
--- a/web-ui/Makefile
+++ b/web-ui/Makefile
@@ -22,13 +22,13 @@ compile:
./go package
clean:
- rm -Rf $(DESTDIR)/
+ rm -Rf dist/ $(DESTDIR)/
install:
rm -Rf $(DESTDIR)/usr/pixelated $(DESTDIR)/usr/web-ui # Fix: delete files generated by python setup.py install that are in the wrong place
install -d $(DESTDIR)/usr/share/pixelated-user-agent
- cp -r public/* $(DESTDIR)/usr/share/pixelated-user-agent
+ cp -r dist/* $(DESTDIR)/usr/share/pixelated-user-agent
all: clean compile install
diff --git a/web-ui/public/404.html b/web-ui/app/404.html
index fdace4ab..fdace4ab 100644
--- a/web-ui/public/404.html
+++ b/web-ui/app/404.html
diff --git a/web-ui/public/favicon.ico b/web-ui/app/favicon.ico
index e69de29b..e69de29b 100644
--- a/web-ui/public/favicon.ico
+++ b/web-ui/app/favicon.ico
diff --git a/web-ui/public/fonts/OpenSans-Bold.woff b/web-ui/app/fonts/OpenSans-Bold.woff
index dacf3c9c..dacf3c9c 100644
--- a/web-ui/public/fonts/OpenSans-Bold.woff
+++ b/web-ui/app/fonts/OpenSans-Bold.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-BoldItalic.woff b/web-ui/app/fonts/OpenSans-BoldItalic.woff
index a4e29c0f..a4e29c0f 100644
--- a/web-ui/public/fonts/OpenSans-BoldItalic.woff
+++ b/web-ui/app/fonts/OpenSans-BoldItalic.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-Extrabold.woff b/web-ui/app/fonts/OpenSans-Extrabold.woff
index 7a2e352b..7a2e352b 100644
--- a/web-ui/public/fonts/OpenSans-Extrabold.woff
+++ b/web-ui/app/fonts/OpenSans-Extrabold.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-ExtraboldItalic.woff b/web-ui/app/fonts/OpenSans-ExtraboldItalic.woff
index ce3ab2e7..ce3ab2e7 100644
--- a/web-ui/public/fonts/OpenSans-ExtraboldItalic.woff
+++ b/web-ui/app/fonts/OpenSans-ExtraboldItalic.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-Italic.woff b/web-ui/app/fonts/OpenSans-Italic.woff
index c5f6bac1..c5f6bac1 100644
--- a/web-ui/public/fonts/OpenSans-Italic.woff
+++ b/web-ui/app/fonts/OpenSans-Italic.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-Light.woff b/web-ui/app/fonts/OpenSans-Light.woff
index eb601d70..eb601d70 100644
--- a/web-ui/public/fonts/OpenSans-Light.woff
+++ b/web-ui/app/fonts/OpenSans-Light.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-Semibold.woff b/web-ui/app/fonts/OpenSans-Semibold.woff
index 56c44944..56c44944 100644
--- a/web-ui/public/fonts/OpenSans-Semibold.woff
+++ b/web-ui/app/fonts/OpenSans-Semibold.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans-SemiboldItalic.woff b/web-ui/app/fonts/OpenSans-SemiboldItalic.woff
index 3a439fc3..3a439fc3 100644
--- a/web-ui/public/fonts/OpenSans-SemiboldItalic.woff
+++ b/web-ui/app/fonts/OpenSans-SemiboldItalic.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSans.woff b/web-ui/app/fonts/OpenSans.woff
index 77706fa6..77706fa6 100644
--- a/web-ui/public/fonts/OpenSans.woff
+++ b/web-ui/app/fonts/OpenSans.woff
Binary files differ
diff --git a/web-ui/public/fonts/OpenSansLight-Italic.woff b/web-ui/app/fonts/OpenSansLight-Italic.woff
index 3f9f088f..3f9f088f 100644
--- a/web-ui/public/fonts/OpenSansLight-Italic.woff
+++ b/web-ui/app/fonts/OpenSansLight-Italic.woff
Binary files differ
diff --git a/web-ui/public/fonts/icomoon.ttf b/web-ui/app/fonts/icomoon.ttf
index 61315d04..61315d04 100644
--- a/web-ui/public/fonts/icomoon.ttf
+++ b/web-ui/app/fonts/icomoon.ttf
Binary files differ
diff --git a/web-ui/public/fonts/icomoon.woff b/web-ui/app/fonts/icomoon.woff
index 82f11748..82f11748 100644
--- a/web-ui/public/fonts/icomoon.woff
+++ b/web-ui/app/fonts/icomoon.woff
Binary files differ
diff --git a/web-ui/src/images/LOADING-transparent.gif b/web-ui/app/images/LOADING-transparent.gif
index ac9abcde..ac9abcde 100644
--- a/web-ui/src/images/LOADING-transparent.gif
+++ b/web-ui/app/images/LOADING-transparent.gif
Binary files differ
diff --git a/web-ui/src/images/fa-sent.svg b/web-ui/app/images/fa-sent.svg
index a4b4bea4..a4b4bea4 100644
--- a/web-ui/src/images/fa-sent.svg
+++ b/web-ui/app/images/fa-sent.svg
diff --git a/web-ui/src/images/favicon.png b/web-ui/app/images/favicon.png
index e14841c7..e14841c7 100644
--- a/web-ui/src/images/favicon.png
+++ b/web-ui/app/images/favicon.png
Binary files differ
diff --git a/web-ui/src/images/logo.svg b/web-ui/app/images/logo.svg
index 6c2d8989..6c2d8989 100644
--- a/web-ui/src/images/logo.svg
+++ b/web-ui/app/images/logo.svg
diff --git a/web-ui/src/images/pixelated-symbol-blue-transparent-01.png b/web-ui/app/images/pixelated-symbol-blue-transparent-01.png
index 96b92155..96b92155 100644
--- a/web-ui/src/images/pixelated-symbol-blue-transparent-01.png
+++ b/web-ui/app/images/pixelated-symbol-blue-transparent-01.png
Binary files differ
diff --git a/service/templates/index.html b/web-ui/app/index.html
index e8bb62ba..4b6a81a0 100644
--- a/service/templates/index.html
+++ b/web-ui/app/index.html
@@ -1,15 +1,15 @@
<!DOCTYPE html>
<html>
<head>
-<link rel="icon" type="image/png" href="static/images/Favicon.png">
+<link rel="icon" type="image/png" href="assets/images/Favicon.png">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>$account_email - Pixelated Mail</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
-<link href="static/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
-<link href="static/bower_components/jquery-file-upload/css/jquery.fileupload.css" rel="stylesheet" type="text/css">
-<link rel="stylesheet" href="static/css/style.css">
+<link href="assets/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+<link href="assets/bower_components/jquery-file-upload/css/jquery.fileupload.css" rel="stylesheet" type="text/css">
+<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
@@ -25,15 +25,15 @@
<path fill="#3E3B38" d="M233.8,678.3h-24v71.2h16.2v-26.5h7.8c14,0,24.3-8,24.3-22.9C258.1,685.6,247.6,678.3,233.8,678.3z
M230.6,710.2h-4.6v-18.8h4.6c6.5,0,12.5,2.2,12.5,9.5C243,708.1,237.1,710.2,230.6,710.2z"/>
<rect x="263.5" y="678.3" fill="#3E3B38" width="16.2" height="71.2"/>
- <polygon fill="#3E3B38" points="350.4,678.3 330.1,678.3 316.9,697.7 303.7,678.3 284.6,678.3 307,711.1 282.6,749.5 302.9,749.5
+ <polygon fill="#3E3B38" points="350.4,678.3 330.1,678.3 316.9,697.7 303.7,678.3 284.6,678.3 307,711.1 282.6,749.5 302.9,749.5
316.9,725.3 331,749.5 352.1,749.5 326.9,711.1 "/>
- <polygon fill="#3E3B38" points="354.7,749.5 395.5,749.5 395.5,735.2 370.9,735.2 370.9,721 394.4,721 394.4,706.6 370.9,706.6
+ <polygon fill="#3E3B38" points="354.7,749.5 395.5,749.5 395.5,735.2 370.9,735.2 370.9,721 394.4,721 394.4,706.6 370.9,706.6
370.9,692.5 395.5,692.5 395.5,678.3 354.7,678.3 "/>
<path fill="#3E3B38" d="M456.1,678.3l-22.9,57h-15.9v-57h-16.2v71.2h26.5h14.3h3.2l5.4-14.3h27l5.4,14.3h17.5l-28.9-71.2H456.1z
M455.7,721l7.8-20.7h0.2l7.8,20.7H455.7z"/>
- <polygon fill="#3E3B38" points="486.4,692.5 503.4,692.5 503.4,749.5 519.6,749.5 519.6,692.5 536.6,692.5 536.6,678.3
+ <polygon fill="#3E3B38" points="486.4,692.5 503.4,692.5 503.4,749.5 519.6,749.5 519.6,692.5 536.6,692.5 536.6,678.3
486.4,678.3 "/>
- <polygon fill="#3E3B38" points="542,749.5 582.8,749.5 582.8,735.2 558.4,735.2 558.4,721 581.9,721 581.9,706.6 558.4,706.6
+ <polygon fill="#3E3B38" points="542,749.5 582.8,749.5 582.8,735.2 558.4,735.2 558.4,721 581.9,721 581.9,706.6 558.4,706.6
558.4,692.5 582.8,692.5 582.8,678.3 542,678.3 "/>
<path fill="#3E3B38" d="M606.5,678.3h-17.9v71.2h17.9c19.7,0,35.9-14.9,35.9-35.6C642.4,693.1,625.9,678.3,606.5,678.3z M607,735
h-2.4v-42.1h2.4c12.1,0,20.3,9.1,20.3,21.1C627.3,725.8,619.1,735,607,735z"/>
@@ -92,8 +92,22 @@
</div>
</div>
-
-<script src="/static/app.min.js" type="text/javascript"></script>
+<!--usemin_start-->
+<script src="assets/bower_components/modernizr/modernizr.js"></script>
+<script src="assets/bower_components/lodash/dist/lodash.js"></script>
+<script src="assets/bower_components/jquery/dist/jquery.js"></script>
+<script src="assets/bower_components/jquery-ui/jquery-ui.min.js"></script>
+<script src="assets/bower_components/jquery-file-upload/js/jquery.fileupload.js"></script>
+<script src="assets/js/lib/highlightRegex.js"></script>
+<script src="assets/bower_components/handlebars/handlebars.min.js"></script>
+<script src="assets/bower_components/typeahead.js/dist/typeahead.bundle.min.js"></script>
+<script src="assets/bower_components/foundation/js/foundation.js" ></script>
+<script src="assets/bower_components/foundation/js/foundation/foundation.reveal.js" ></script>
+<script src="assets/bower_components/foundation/js/foundation/foundation.offcanvas.js"></script>
+<script src="assets/js/foundation/initialize_foundation.js"></script>
+<script src="assets/bower_components/iframe-resizer/js/iframeResizer.min.js"></script>
+<script src="assets/bower_components/requirejs/require.js" data-main="assets/js/main.js"></script>
+<!--usemin_end-->
</body>
</html>
diff --git a/web-ui/public/js/dispatchers/left_pane_dispatcher.js b/web-ui/app/js/dispatchers/left_pane_dispatcher.js
index 0037a88f..0037a88f 100644
--- a/web-ui/public/js/dispatchers/left_pane_dispatcher.js
+++ b/web-ui/app/js/dispatchers/left_pane_dispatcher.js
diff --git a/web-ui/public/js/dispatchers/middle_pane_dispatcher.js b/web-ui/app/js/dispatchers/middle_pane_dispatcher.js
index 12222aec..12222aec 100644
--- a/web-ui/public/js/dispatchers/middle_pane_dispatcher.js
+++ b/web-ui/app/js/dispatchers/middle_pane_dispatcher.js
diff --git a/web-ui/public/js/dispatchers/right_pane_dispatcher.js b/web-ui/app/js/dispatchers/right_pane_dispatcher.js
index 870bcd92..870bcd92 100644
--- a/web-ui/public/js/dispatchers/right_pane_dispatcher.js
+++ b/web-ui/app/js/dispatchers/right_pane_dispatcher.js
diff --git a/web-ui/public/js/features/features.js b/web-ui/app/js/features/features.js
index f71d56ea..f71d56ea 100644
--- a/web-ui/public/js/features/features.js
+++ b/web-ui/app/js/features/features.js
diff --git a/web-ui/public/js/feedback/feedback_cache.js b/web-ui/app/js/feedback/feedback_cache.js
index a5d92266..a5d92266 100644
--- a/web-ui/public/js/feedback/feedback_cache.js
+++ b/web-ui/app/js/feedback/feedback_cache.js
diff --git a/web-ui/public/js/feedback/feedback_trigger.js b/web-ui/app/js/feedback/feedback_trigger.js
index 598f9060..598f9060 100644
--- a/web-ui/public/js/feedback/feedback_trigger.js
+++ b/web-ui/app/js/feedback/feedback_trigger.js
diff --git a/web-ui/public/js/foundation/initialize_foundation.js b/web-ui/app/js/foundation/initialize_foundation.js
index 42405dfe..42405dfe 100644
--- a/web-ui/public/js/foundation/initialize_foundation.js
+++ b/web-ui/app/js/foundation/initialize_foundation.js
diff --git a/web-ui/public/js/foundation/off_canvas.js b/web-ui/app/js/foundation/off_canvas.js
index 66334470..66334470 100644
--- a/web-ui/public/js/foundation/off_canvas.js
+++ b/web-ui/app/js/foundation/off_canvas.js
diff --git a/web-ui/public/js/helpers/browser.js b/web-ui/app/js/helpers/browser.js
index dacf2263..dacf2263 100644
--- a/web-ui/public/js/helpers/browser.js
+++ b/web-ui/app/js/helpers/browser.js
diff --git a/web-ui/public/js/helpers/contenttype.js b/web-ui/app/js/helpers/contenttype.js
index a1e5361a..a1e5361a 100644
--- a/web-ui/public/js/helpers/contenttype.js
+++ b/web-ui/app/js/helpers/contenttype.js
diff --git a/web-ui/public/js/helpers/iterator.js b/web-ui/app/js/helpers/iterator.js
index 236c7a40..236c7a40 100644
--- a/web-ui/public/js/helpers/iterator.js
+++ b/web-ui/app/js/helpers/iterator.js
diff --git a/web-ui/public/js/helpers/monitored_ajax.js b/web-ui/app/js/helpers/monitored_ajax.js
index bbf85c45..bbf85c45 100644
--- a/web-ui/public/js/helpers/monitored_ajax.js
+++ b/web-ui/app/js/helpers/monitored_ajax.js
diff --git a/web-ui/public/js/helpers/sanitizer.js b/web-ui/app/js/helpers/sanitizer.js
index 443e8602..443e8602 100644
--- a/web-ui/public/js/helpers/sanitizer.js
+++ b/web-ui/app/js/helpers/sanitizer.js
diff --git a/web-ui/public/js/helpers/triggering.js b/web-ui/app/js/helpers/triggering.js
index d26d9fc6..d26d9fc6 100644
--- a/web-ui/public/js/helpers/triggering.js
+++ b/web-ui/app/js/helpers/triggering.js
diff --git a/web-ui/public/js/helpers/view_helper.js b/web-ui/app/js/helpers/view_helper.js
index ed9e0559..ed9e0559 100644
--- a/web-ui/public/js/helpers/view_helper.js
+++ b/web-ui/app/js/helpers/view_helper.js
diff --git a/web-ui/public/js/lib/highlightRegex.js b/web-ui/app/js/lib/highlightRegex.js
index 17caaa23..17caaa23 100644
--- a/web-ui/public/js/lib/highlightRegex.js
+++ b/web-ui/app/js/lib/highlightRegex.js
diff --git a/web-ui/public/js/lib/html4-defs.js b/web-ui/app/js/lib/html4-defs.js
index 1ec575da..1ec575da 100644
--- a/web-ui/public/js/lib/html4-defs.js
+++ b/web-ui/app/js/lib/html4-defs.js
diff --git a/web-ui/public/js/mail_list/domain/refresher.js b/web-ui/app/js/mail_list/domain/refresher.js
index 38c9cde5..38c9cde5 100644
--- a/web-ui/public/js/mail_list/domain/refresher.js
+++ b/web-ui/app/js/mail_list/domain/refresher.js
diff --git a/web-ui/public/js/mail_list/ui/mail_item_factory.js b/web-ui/app/js/mail_list/ui/mail_item_factory.js
index 7205d35c..7205d35c 100644
--- a/web-ui/public/js/mail_list/ui/mail_item_factory.js
+++ b/web-ui/app/js/mail_list/ui/mail_item_factory.js
diff --git a/web-ui/public/js/mail_list/ui/mail_items/draft_item.js b/web-ui/app/js/mail_list/ui/mail_items/draft_item.js
index 57fbafd5..57fbafd5 100644
--- a/web-ui/public/js/mail_list/ui/mail_items/draft_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/draft_item.js
diff --git a/web-ui/public/js/mail_list/ui/mail_items/generic_mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js
index 939f7e1b..939f7e1b 100644
--- a/web-ui/public/js/mail_list/ui/mail_items/generic_mail_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/generic_mail_item.js
diff --git a/web-ui/public/js/mail_list/ui/mail_items/mail_item.js b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js
index be664289..be664289 100644
--- a/web-ui/public/js/mail_list/ui/mail_items/mail_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/mail_item.js
diff --git a/web-ui/public/js/mail_list/ui/mail_items/sent_item.js b/web-ui/app/js/mail_list/ui/mail_items/sent_item.js
index 9e511068..9e511068 100644
--- a/web-ui/public/js/mail_list/ui/mail_items/sent_item.js
+++ b/web-ui/app/js/mail_list/ui/mail_items/sent_item.js
diff --git a/web-ui/public/js/mail_list/ui/mail_list.js b/web-ui/app/js/mail_list/ui/mail_list.js
index af4821a8..af4821a8 100644
--- a/web-ui/public/js/mail_list/ui/mail_list.js
+++ b/web-ui/app/js/mail_list/ui/mail_list.js
diff --git a/web-ui/public/js/mail_list_actions/ui/archive_many_trigger.js b/web-ui/app/js/mail_list_actions/ui/archive_many_trigger.js
index b148cdce..b148cdce 100644
--- a/web-ui/public/js/mail_list_actions/ui/archive_many_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/archive_many_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/compose_trigger.js b/web-ui/app/js/mail_list_actions/ui/compose_trigger.js
index ec79cb26..ec79cb26 100644
--- a/web-ui/public/js/mail_list_actions/ui/compose_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/compose_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/delete_many_trigger.js b/web-ui/app/js/mail_list_actions/ui/delete_many_trigger.js
index dd2f67a5..dd2f67a5 100644
--- a/web-ui/public/js/mail_list_actions/ui/delete_many_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/delete_many_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/mail_list_actions.js b/web-ui/app/js/mail_list_actions/ui/mail_list_actions.js
index 69e5fde4..69e5fde4 100644
--- a/web-ui/public/js/mail_list_actions/ui/mail_list_actions.js
+++ b/web-ui/app/js/mail_list_actions/ui/mail_list_actions.js
diff --git a/web-ui/public/js/mail_list_actions/ui/mark_as_unread_trigger.js b/web-ui/app/js/mail_list_actions/ui/mark_as_unread_trigger.js
index 2584e453..2584e453 100644
--- a/web-ui/public/js/mail_list_actions/ui/mark_as_unread_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/mark_as_unread_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/mark_many_as_read_trigger.js b/web-ui/app/js/mail_list_actions/ui/mark_many_as_read_trigger.js
index c16a2229..c16a2229 100644
--- a/web-ui/public/js/mail_list_actions/ui/mark_many_as_read_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/mark_many_as_read_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/pagination_trigger.js b/web-ui/app/js/mail_list_actions/ui/pagination_trigger.js
index 3bc13d40..3bc13d40 100644
--- a/web-ui/public/js/mail_list_actions/ui/pagination_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/pagination_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/recover_many_trigger.js b/web-ui/app/js/mail_list_actions/ui/recover_many_trigger.js
index e0a32094..e0a32094 100644
--- a/web-ui/public/js/mail_list_actions/ui/recover_many_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/recover_many_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/refresh_trigger.js b/web-ui/app/js/mail_list_actions/ui/refresh_trigger.js
index a16270d2..a16270d2 100644
--- a/web-ui/public/js/mail_list_actions/ui/refresh_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/refresh_trigger.js
diff --git a/web-ui/public/js/mail_list_actions/ui/toggle_check_all_trigger.js b/web-ui/app/js/mail_list_actions/ui/toggle_check_all_trigger.js
index 71c65346..71c65346 100644
--- a/web-ui/public/js/mail_list_actions/ui/toggle_check_all_trigger.js
+++ b/web-ui/app/js/mail_list_actions/ui/toggle_check_all_trigger.js
diff --git a/web-ui/public/js/mail_view/data/feedback_sender.js b/web-ui/app/js/mail_view/data/feedback_sender.js
index 2232dbe4..2232dbe4 100644
--- a/web-ui/public/js/mail_view/data/feedback_sender.js
+++ b/web-ui/app/js/mail_view/data/feedback_sender.js
diff --git a/web-ui/public/js/mail_view/data/mail_builder.js b/web-ui/app/js/mail_view/data/mail_builder.js
index 7a478dd8..7a478dd8 100644
--- a/web-ui/public/js/mail_view/data/mail_builder.js
+++ b/web-ui/app/js/mail_view/data/mail_builder.js
diff --git a/web-ui/public/js/mail_view/data/mail_sender.js b/web-ui/app/js/mail_view/data/mail_sender.js
index 8bb01f70..8bb01f70 100644
--- a/web-ui/public/js/mail_view/data/mail_sender.js
+++ b/web-ui/app/js/mail_view/data/mail_sender.js
diff --git a/web-ui/public/js/mail_view/ui/attachment_icon.js b/web-ui/app/js/mail_view/ui/attachment_icon.js
index e04fc02a..e04fc02a 100644
--- a/web-ui/public/js/mail_view/ui/attachment_icon.js
+++ b/web-ui/app/js/mail_view/ui/attachment_icon.js
diff --git a/web-ui/public/js/mail_view/ui/attachment_list.js b/web-ui/app/js/mail_view/ui/attachment_list.js
index 4ef64960..4ef64960 100644
--- a/web-ui/public/js/mail_view/ui/attachment_list.js
+++ b/web-ui/app/js/mail_view/ui/attachment_list.js
diff --git a/web-ui/public/js/mail_view/ui/compose_box.js b/web-ui/app/js/mail_view/ui/compose_box.js
index 101dc939..101dc939 100644
--- a/web-ui/public/js/mail_view/ui/compose_box.js
+++ b/web-ui/app/js/mail_view/ui/compose_box.js
diff --git a/web-ui/public/js/mail_view/ui/draft_box.js b/web-ui/app/js/mail_view/ui/draft_box.js
index afe31914..afe31914 100644
--- a/web-ui/public/js/mail_view/ui/draft_box.js
+++ b/web-ui/app/js/mail_view/ui/draft_box.js
diff --git a/web-ui/public/js/mail_view/ui/draft_save_status.js b/web-ui/app/js/mail_view/ui/draft_save_status.js
index 47751d91..47751d91 100644
--- a/web-ui/public/js/mail_view/ui/draft_save_status.js
+++ b/web-ui/app/js/mail_view/ui/draft_save_status.js
diff --git a/web-ui/public/js/mail_view/ui/feedback_box.js b/web-ui/app/js/mail_view/ui/feedback_box.js
index 4e00ece8..4e00ece8 100644
--- a/web-ui/public/js/mail_view/ui/feedback_box.js
+++ b/web-ui/app/js/mail_view/ui/feedback_box.js
diff --git a/web-ui/public/js/mail_view/ui/forward_box.js b/web-ui/app/js/mail_view/ui/forward_box.js
index a34bd55d..a34bd55d 100644
--- a/web-ui/public/js/mail_view/ui/forward_box.js
+++ b/web-ui/app/js/mail_view/ui/forward_box.js
diff --git a/web-ui/public/js/mail_view/ui/mail_actions.js b/web-ui/app/js/mail_view/ui/mail_actions.js
index 65cd0aaa..65cd0aaa 100644
--- a/web-ui/public/js/mail_view/ui/mail_actions.js
+++ b/web-ui/app/js/mail_view/ui/mail_actions.js
diff --git a/web-ui/public/js/mail_view/ui/mail_view.js b/web-ui/app/js/mail_view/ui/mail_view.js
index 3408c8af..3408c8af 100644
--- a/web-ui/public/js/mail_view/ui/mail_view.js
+++ b/web-ui/app/js/mail_view/ui/mail_view.js
diff --git a/web-ui/public/js/mail_view/ui/no_mails_available_pane.js b/web-ui/app/js/mail_view/ui/no_mails_available_pane.js
index c62c6b30..c62c6b30 100644
--- a/web-ui/public/js/mail_view/ui/no_mails_available_pane.js
+++ b/web-ui/app/js/mail_view/ui/no_mails_available_pane.js
diff --git a/web-ui/public/js/mail_view/ui/no_message_selected_pane.js b/web-ui/app/js/mail_view/ui/no_message_selected_pane.js
index a5fc2393..a5fc2393 100644
--- a/web-ui/public/js/mail_view/ui/no_message_selected_pane.js
+++ b/web-ui/app/js/mail_view/ui/no_message_selected_pane.js
diff --git a/web-ui/public/js/mail_view/ui/recipients/recipient.js b/web-ui/app/js/mail_view/ui/recipients/recipient.js
index c13a52b1..c13a52b1 100644
--- a/web-ui/public/js/mail_view/ui/recipients/recipient.js
+++ b/web-ui/app/js/mail_view/ui/recipients/recipient.js
diff --git a/web-ui/public/js/mail_view/ui/recipients/recipients.js b/web-ui/app/js/mail_view/ui/recipients/recipients.js
index 2caa8d14..2caa8d14 100644
--- a/web-ui/public/js/mail_view/ui/recipients/recipients.js
+++ b/web-ui/app/js/mail_view/ui/recipients/recipients.js
diff --git a/web-ui/public/js/mail_view/ui/recipients/recipients_input.js b/web-ui/app/js/mail_view/ui/recipients/recipients_input.js
index 8a9c4eaf..8a9c4eaf 100644
--- a/web-ui/public/js/mail_view/ui/recipients/recipients_input.js
+++ b/web-ui/app/js/mail_view/ui/recipients/recipients_input.js
diff --git a/web-ui/public/js/mail_view/ui/recipients/recipients_iterator.js b/web-ui/app/js/mail_view/ui/recipients/recipients_iterator.js
index 624ac4f5..624ac4f5 100644
--- a/web-ui/public/js/mail_view/ui/recipients/recipients_iterator.js
+++ b/web-ui/app/js/mail_view/ui/recipients/recipients_iterator.js
diff --git a/web-ui/public/js/mail_view/ui/reply_box.js b/web-ui/app/js/mail_view/ui/reply_box.js
index a174d185..a174d185 100644
--- a/web-ui/public/js/mail_view/ui/reply_box.js
+++ b/web-ui/app/js/mail_view/ui/reply_box.js
diff --git a/web-ui/public/js/mail_view/ui/reply_section.js b/web-ui/app/js/mail_view/ui/reply_section.js
index cbe64205..cbe64205 100644
--- a/web-ui/public/js/mail_view/ui/reply_section.js
+++ b/web-ui/app/js/mail_view/ui/reply_section.js
diff --git a/web-ui/public/js/mail_view/ui/send_button.js b/web-ui/app/js/mail_view/ui/send_button.js
index 66fe1233..66fe1233 100644
--- a/web-ui/public/js/mail_view/ui/send_button.js
+++ b/web-ui/app/js/mail_view/ui/send_button.js
diff --git a/web-ui/public/js/main.js b/web-ui/app/js/main.js
index 1aeb1a63..b8836a6b 100644
--- a/web-ui/public/js/main.js
+++ b/web-ui/app/js/main.js
@@ -16,7 +16,7 @@
*/
requirejs.config({
- baseUrl: '../static/',
+ baseUrl: '../assets/',
paths: {
'mail_list': 'js/mail_list',
'page': 'js/page',
diff --git a/web-ui/public/js/mixins/with_auto_refresh.js b/web-ui/app/js/mixins/with_auto_refresh.js
index c75fda45..c75fda45 100644
--- a/web-ui/public/js/mixins/with_auto_refresh.js
+++ b/web-ui/app/js/mixins/with_auto_refresh.js
diff --git a/web-ui/public/js/mixins/with_compose_inline.js b/web-ui/app/js/mixins/with_compose_inline.js
index b8266f28..b8266f28 100644
--- a/web-ui/public/js/mixins/with_compose_inline.js
+++ b/web-ui/app/js/mixins/with_compose_inline.js
diff --git a/web-ui/public/js/mixins/with_enable_disable_on_event.js b/web-ui/app/js/mixins/with_enable_disable_on_event.js
index 5b28a67b..5b28a67b 100644
--- a/web-ui/public/js/mixins/with_enable_disable_on_event.js
+++ b/web-ui/app/js/mixins/with_enable_disable_on_event.js
diff --git a/web-ui/public/js/mixins/with_feature_toggle.js b/web-ui/app/js/mixins/with_feature_toggle.js
index 195b08bc..195b08bc 100644
--- a/web-ui/public/js/mixins/with_feature_toggle.js
+++ b/web-ui/app/js/mixins/with_feature_toggle.js
diff --git a/web-ui/public/js/mixins/with_hide_and_show.js b/web-ui/app/js/mixins/with_hide_and_show.js
index c8902f61..c8902f61 100644
--- a/web-ui/public/js/mixins/with_hide_and_show.js
+++ b/web-ui/app/js/mixins/with_hide_and_show.js
diff --git a/web-ui/public/js/mixins/with_mail_edit_base.js b/web-ui/app/js/mixins/with_mail_edit_base.js
index a088080e..a088080e 100644
--- a/web-ui/public/js/mixins/with_mail_edit_base.js
+++ b/web-ui/app/js/mixins/with_mail_edit_base.js
diff --git a/web-ui/public/js/mixins/with_mail_sandbox.js b/web-ui/app/js/mixins/with_mail_sandbox.js
index 1a51840d..1a51840d 100644
--- a/web-ui/public/js/mixins/with_mail_sandbox.js
+++ b/web-ui/app/js/mixins/with_mail_sandbox.js
diff --git a/web-ui/public/js/mixins/with_mail_tagging.js b/web-ui/app/js/mixins/with_mail_tagging.js
index 1fc1c3bd..1fc1c3bd 100644
--- a/web-ui/public/js/mixins/with_mail_tagging.js
+++ b/web-ui/app/js/mixins/with_mail_tagging.js
diff --git a/web-ui/public/js/monkey_patching/all.js b/web-ui/app/js/monkey_patching/all.js
index 2c29c9a1..2c29c9a1 100644
--- a/web-ui/public/js/monkey_patching/all.js
+++ b/web-ui/app/js/monkey_patching/all.js
diff --git a/web-ui/public/js/monkey_patching/array.js b/web-ui/app/js/monkey_patching/array.js
index d0ccc4b8..d0ccc4b8 100644
--- a/web-ui/public/js/monkey_patching/array.js
+++ b/web-ui/app/js/monkey_patching/array.js
diff --git a/web-ui/public/js/monkey_patching/post_message.js b/web-ui/app/js/monkey_patching/post_message.js
index 363ce581..363ce581 100644
--- a/web-ui/public/js/monkey_patching/post_message.js
+++ b/web-ui/app/js/monkey_patching/post_message.js
diff --git a/web-ui/public/js/page/default.js b/web-ui/app/js/page/default.js
index 5d52e06c..ecaedfd8 100644
--- a/web-ui/public/js/page/default.js
+++ b/web-ui/app/js/page/default.js
@@ -96,7 +96,7 @@ define(
'use strict';
function initialize(path) {
- viewI18n.init(path + '/static/');
+ viewI18n.init(path + '/assets/');
viewI18n.loaded(function() {
paneContractExpand.attachTo(document);
diff --git a/web-ui/public/js/page/events.js b/web-ui/app/js/page/events.js
index 68a6aad1..68a6aad1 100644
--- a/web-ui/public/js/page/events.js
+++ b/web-ui/app/js/page/events.js
diff --git a/web-ui/public/js/page/logout.js b/web-ui/app/js/page/logout.js
index 81b57db2..81b57db2 100644
--- a/web-ui/public/js/page/logout.js
+++ b/web-ui/app/js/page/logout.js
diff --git a/web-ui/public/js/page/logout_shortcut.js b/web-ui/app/js/page/logout_shortcut.js
index 10a69c7d..10a69c7d 100644
--- a/web-ui/public/js/page/logout_shortcut.js
+++ b/web-ui/app/js/page/logout_shortcut.js
diff --git a/web-ui/public/js/page/pane_contract_expand.js b/web-ui/app/js/page/pane_contract_expand.js
index 9bb435c4..9bb435c4 100644
--- a/web-ui/public/js/page/pane_contract_expand.js
+++ b/web-ui/app/js/page/pane_contract_expand.js
diff --git a/web-ui/public/js/page/pix_logo.js b/web-ui/app/js/page/pix_logo.js
index ad17f3be..ad17f3be 100644
--- a/web-ui/public/js/page/pix_logo.js
+++ b/web-ui/app/js/page/pix_logo.js
diff --git a/web-ui/public/js/page/router.js b/web-ui/app/js/page/router.js
index ce0d7d04..ce0d7d04 100644
--- a/web-ui/public/js/page/router.js
+++ b/web-ui/app/js/page/router.js
diff --git a/web-ui/public/js/page/router/url_params.js b/web-ui/app/js/page/router/url_params.js
index 4fa11c6d..4fa11c6d 100644
--- a/web-ui/public/js/page/router/url_params.js
+++ b/web-ui/app/js/page/router/url_params.js
diff --git a/web-ui/public/js/page/unread_count_title.js b/web-ui/app/js/page/unread_count_title.js
index 89dcd47d..89dcd47d 100644
--- a/web-ui/public/js/page/unread_count_title.js
+++ b/web-ui/app/js/page/unread_count_title.js
diff --git a/web-ui/public/js/page/version.js b/web-ui/app/js/page/version.js
index 9fd5e629..9fd5e629 100644
--- a/web-ui/public/js/page/version.js
+++ b/web-ui/app/js/page/version.js
diff --git a/web-ui/public/js/sandbox.js b/web-ui/app/js/sandbox.js
index 33b16ea4..33b16ea4 100644
--- a/web-ui/public/js/sandbox.js
+++ b/web-ui/app/js/sandbox.js
diff --git a/web-ui/public/js/search/results_highlighter.js b/web-ui/app/js/search/results_highlighter.js
index 831be0cd..831be0cd 100644
--- a/web-ui/public/js/search/results_highlighter.js
+++ b/web-ui/app/js/search/results_highlighter.js
diff --git a/web-ui/public/js/search/search_trigger.js b/web-ui/app/js/search/search_trigger.js
index 2aff027c..2aff027c 100644
--- a/web-ui/public/js/search/search_trigger.js
+++ b/web-ui/app/js/search/search_trigger.js
diff --git a/web-ui/public/js/services/delete_service.js b/web-ui/app/js/services/delete_service.js
index 0dfc1bdb..0dfc1bdb 100644
--- a/web-ui/public/js/services/delete_service.js
+++ b/web-ui/app/js/services/delete_service.js
diff --git a/web-ui/public/js/services/mail_service.js b/web-ui/app/js/services/mail_service.js
index 5e4bd4f3..5e4bd4f3 100644
--- a/web-ui/public/js/services/mail_service.js
+++ b/web-ui/app/js/services/mail_service.js
diff --git a/web-ui/public/js/services/model/mail.js b/web-ui/app/js/services/model/mail.js
index 64a10c1c..64a10c1c 100644
--- a/web-ui/public/js/services/model/mail.js
+++ b/web-ui/app/js/services/model/mail.js
diff --git a/web-ui/public/js/services/recover_service.js b/web-ui/app/js/services/recover_service.js
index d7d9cdc9..d7d9cdc9 100644
--- a/web-ui/public/js/services/recover_service.js
+++ b/web-ui/app/js/services/recover_service.js
diff --git a/web-ui/public/js/style_guide/main.js b/web-ui/app/js/style_guide/main.js
index 32c213cf..32c213cf 100644
--- a/web-ui/public/js/style_guide/main.js
+++ b/web-ui/app/js/style_guide/main.js
diff --git a/web-ui/public/js/tags/data/tags.js b/web-ui/app/js/tags/data/tags.js
index 31703b2a..31703b2a 100644
--- a/web-ui/public/js/tags/data/tags.js
+++ b/web-ui/app/js/tags/data/tags.js
diff --git a/web-ui/public/js/tags/ui/tag.js b/web-ui/app/js/tags/ui/tag.js
index 37814cfc..37814cfc 100644
--- a/web-ui/public/js/tags/ui/tag.js
+++ b/web-ui/app/js/tags/ui/tag.js
diff --git a/web-ui/public/js/tags/ui/tag_base.js b/web-ui/app/js/tags/ui/tag_base.js
index 9dc1ccbb..9dc1ccbb 100644
--- a/web-ui/public/js/tags/ui/tag_base.js
+++ b/web-ui/app/js/tags/ui/tag_base.js
diff --git a/web-ui/public/js/tags/ui/tag_list.js b/web-ui/app/js/tags/ui/tag_list.js
index a2172c6d..a2172c6d 100644
--- a/web-ui/public/js/tags/ui/tag_list.js
+++ b/web-ui/app/js/tags/ui/tag_list.js
diff --git a/web-ui/public/js/user_alerts/ui/user_alerts.js b/web-ui/app/js/user_alerts/ui/user_alerts.js
index e944a7a5..e944a7a5 100644
--- a/web-ui/public/js/user_alerts/ui/user_alerts.js
+++ b/web-ui/app/js/user_alerts/ui/user_alerts.js
diff --git a/web-ui/public/js/user_settings/data/user_settings.js b/web-ui/app/js/user_settings/data/user_settings.js
index dac29cec..dac29cec 100644
--- a/web-ui/public/js/user_settings/data/user_settings.js
+++ b/web-ui/app/js/user_settings/data/user_settings.js
diff --git a/web-ui/public/js/user_settings/ui/user_settings_box.js b/web-ui/app/js/user_settings/ui/user_settings_box.js
index d3de23ed..d3de23ed 100644
--- a/web-ui/public/js/user_settings/ui/user_settings_box.js
+++ b/web-ui/app/js/user_settings/ui/user_settings_box.js
diff --git a/web-ui/public/js/user_settings/ui/user_settings_icon.js b/web-ui/app/js/user_settings/ui/user_settings_icon.js
index a6385dc1..a6385dc1 100644
--- a/web-ui/public/js/user_settings/ui/user_settings_icon.js
+++ b/web-ui/app/js/user_settings/ui/user_settings_icon.js
diff --git a/web-ui/public/js/views/i18n.js b/web-ui/app/js/views/i18n.js
index 29a1beca..29a1beca 100644
--- a/web-ui/public/js/views/i18n.js
+++ b/web-ui/app/js/views/i18n.js
diff --git a/web-ui/public/js/views/recipientListFormatter.js b/web-ui/app/js/views/recipientListFormatter.js
index 0b887142..0b887142 100644
--- a/web-ui/public/js/views/recipientListFormatter.js
+++ b/web-ui/app/js/views/recipientListFormatter.js
diff --git a/web-ui/app/js/views/templates.js b/web-ui/app/js/views/templates.js
new file mode 100644
index 00000000..d4185471
--- /dev/null
+++ b/web-ui/app/js/views/templates.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define(['hbs/templates'], function (templates) {
+ 'use strict';
+
+ var Templates = {
+ compose: {
+ box: window.Pixelated['app/templates/compose/compose_box.hbs'],
+ inlineBox: window.Pixelated['app/templates/compose/inline_box.hbs'],
+ replySection: window.Pixelated['app/templates/compose/reply_section.hbs'],
+ recipientInput: window.Pixelated['app/templates/compose/recipient_input.hbs'],
+ fixedRecipient: window.Pixelated['app/templates/compose/fixed_recipient.hbs'],
+ recipients: window.Pixelated['app/templates/compose/recipients.hbs'],
+ feedback: window.Pixelated['app/templates/compose/feedback_box.hbs'],
+ attachmentsList: window.Pixelated['app/templates/compose/attachments_list.hbs'],
+ attachmentItem: window.Pixelated['app/templates/compose/attachment_item.hbs'],
+ attachmentUploadItem: window.Pixelated['app/templates/compose/attachment_upload_item.hbs'],
+ uploadAttachmentFailed: window.Pixelated['app/templates/compose/upload_attachment_failed.hbs']
+ },
+ tags: {
+ tagList: window.Pixelated['app/templates/tags/tag_list.hbs'],
+ tag: window.Pixelated['app/templates/tags/tag.hbs'],
+ tagInner: window.Pixelated['app/templates/tags/tag_inner.hbs'],
+ shortcut: window.Pixelated['app/templates/tags/shortcut.hbs']
+ },
+ userAlerts: {
+ message: window.Pixelated['app/templates/user_alerts/message.hbs']
+ },
+ mails: {
+ single: window.Pixelated['app/templates/mails/single.hbs'],
+ fullView: window.Pixelated['app/templates/mails/full_view.hbs'],
+ mailActions: window.Pixelated['app/templates/mails/mail_actions.hbs'],
+ draft: window.Pixelated['app/templates/mails/draft.hbs'],
+ sent: window.Pixelated['app/templates/mails/sent.hbs'],
+ trash: window.Pixelated['app/templates/mails/trash.hbs']
+ },
+ mailActions: {
+ actionsBox: window.Pixelated['app/templates/mail_actions/actions_box.hbs'],
+ trashActionsBox: window.Pixelated['app/templates/mail_actions/trash_actions_box.hbs'],
+ composeTrigger: window.Pixelated['app/templates/mail_actions/compose_trigger.hbs'],
+ refreshTrigger: window.Pixelated['app/templates/mail_actions/refresh_trigger.hbs'],
+ paginationTrigger: window.Pixelated['app/templates/mail_actions/pagination_trigger.hbs']
+ },
+ noMessageSelected: window.Pixelated['app/templates/compose/no_message_selected.hbs'],
+ noMailsAvailable: window.Pixelated['app/templates/compose/no_mails_available.hbs'],
+ search: {
+ trigger: window.Pixelated['app/templates/search/search_trigger.hbs']
+ },
+ page: {
+ userSettingsIcon: window.Pixelated['app/templates/page/user_settings_icon.hbs'],
+ userSettingsBox: window.Pixelated['app/templates/page/user_settings_box.hbs'],
+ logout: window.Pixelated['app/templates/page/logout.hbs'],
+ logoutShortcut: window.Pixelated['app/templates/page/logout_shortcut.hbs'],
+ version: window.Pixelated['app/templates/page/version.hbs']
+ },
+ feedback: {
+ feedback: window.Pixelated['app/templates/feedback/feedback_trigger.hbs']
+ }
+ };
+
+ Handlebars.registerPartial('tag_inner', Templates.tags.tagInner);
+ Handlebars.registerPartial('recipients', Templates.compose.recipients);
+ Handlebars.registerPartial('attachments_list', Templates.compose.attachmentsList);
+ Handlebars.registerPartial('attachments_upload', Templates.compose.attachmentsList);
+ Handlebars.registerPartial('attachment_item', Templates.compose.attachmentItem);
+ Handlebars.registerPartial('attachment_upload_item', Templates.compose.attachmentUploadItem);
+ Handlebars.registerPartial('uploadAttachmentFailed', Templates.compose.uploadAttachmentFailed);
+
+ return Templates;
+});
diff --git a/web-ui/public/locales/en_US/translation.json b/web-ui/app/locales/en_US/translation.json
index 3e006156..3e006156 100644
--- a/web-ui/public/locales/en_US/translation.json
+++ b/web-ui/app/locales/en_US/translation.json
diff --git a/web-ui/public/locales/pt_BR/translation.json b/web-ui/app/locales/pt_BR/translation.json
index ff766a2b..ff766a2b 100644
--- a/web-ui/public/locales/pt_BR/translation.json
+++ b/web-ui/app/locales/pt_BR/translation.json
diff --git a/web-ui/public/locales/sv_SE/translation.json b/web-ui/app/locales/sv_SE/translation.json
index d4da0711..d4da0711 100644
--- a/web-ui/public/locales/sv_SE/translation.json
+++ b/web-ui/app/locales/sv_SE/translation.json
diff --git a/web-ui/public/robots.txt b/web-ui/app/robots.txt
index 6b0157e2..6b0157e2 100644
--- a/web-ui/public/robots.txt
+++ b/web-ui/app/robots.txt
diff --git a/web-ui/app/sandbox.html b/web-ui/app/sandbox.html
new file mode 100644
index 00000000..8325b0da
--- /dev/null
+++ b/web-ui/app/sandbox.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="utf-8">
+ <link href="css/sandbox.css" rel="stylesheet" type="text/css">
+
+ <!--usemin_start-->
+ <script src="js/sandbox.js"></script>
+ <script src="bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js"></script>
+ <!--usemin_end-->
+</head>
+
+<body></body>
+
+</html>
diff --git a/web-ui/public/scss/_mixins.scss b/web-ui/app/scss/_mixins.scss
index d3aa0220..d3aa0220 100644
--- a/web-ui/public/scss/_mixins.scss
+++ b/web-ui/app/scss/_mixins.scss
diff --git a/web-ui/public/scss/_others.scss b/web-ui/app/scss/_others.scss
index 039d94bd..039d94bd 100644
--- a/web-ui/public/scss/_others.scss
+++ b/web-ui/app/scss/_others.scss
diff --git a/web-ui/public/scss/base/_colors.scss b/web-ui/app/scss/base/_colors.scss
index 17333ff9..17333ff9 100644
--- a/web-ui/public/scss/base/_colors.scss
+++ b/web-ui/app/scss/base/_colors.scss
diff --git a/web-ui/public/scss/base/_fonts.scss b/web-ui/app/scss/base/_fonts.scss
index a8f2d7da..dfc56dd8 100644
--- a/web-ui/public/scss/base/_fonts.scss
+++ b/web-ui/app/scss/base/_fonts.scss
@@ -2,67 +2,67 @@
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
- src: local('Open Sans Light'), local('OpenSans-Light'), url('/static/fonts/OpenSans-Light.woff') format('woff');
+ src: local('Open Sans Light'), local('OpenSans-Light'), url('/assets/fonts/OpenSans-Light.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
- src: local('Open Sans'), local('OpenSans'), url('/static/fonts/OpenSans.woff') format('woff');
+ src: local('Open Sans'), local('OpenSans'), url('/assets/fonts/OpenSans.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
- src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/static/fonts/OpenSans-Semibold.woff') format('woff');
+ src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/assets/fonts/OpenSans-Semibold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
- src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/static/fonts/OpenSans-Bold.woff') format('woff');
+ src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/assets/fonts/OpenSans-Bold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 800;
- src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/static/fonts/OpenSans-Extrabold.woff') format('woff');
+ src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/assets/fonts/OpenSans-Extrabold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
- src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/static/fonts/OpenSansLight-Italic.woff') format('woff');
+ src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/assets/fonts/OpenSansLight-Italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
- src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/static/fonts/OpenSans-Italic.woff') format('woff');
+ src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/assets/fonts/OpenSans-Italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
- src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/static/fonts/OpenSans-SemiboldItalic.woff') format('woff');
+ src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/assets/fonts/OpenSans-SemiboldItalic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
- src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/static/fonts/OpenSans-BoldItalic.woff') format('woff');
+ src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/assets/fonts/OpenSans-BoldItalic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 800;
- src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/static/fonts/OpenSans-ExtraboldItalic.woff') format('woff');
+ src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/assets/fonts/OpenSans-ExtraboldItalic.woff') format('woff');
}
@font-face {
font-family: 'icomoon';
font-style: normal;
font-weight: 400;
- src: url('/static/fonts/icomoon.woff') format('woff'), url('/static/fonts/icomoon.ttf') format('truetype'), ;
+ src: url('/assets/fonts/icomoon.woff') format('woff'), url('/assets/fonts/icomoon.ttf') format('truetype'), ;
}
diff --git a/web-ui/public/scss/base/_scaffolding.scss b/web-ui/app/scss/base/_scaffolding.scss
index b8b5fa3b..b8b5fa3b 100644
--- a/web-ui/public/scss/base/_scaffolding.scss
+++ b/web-ui/app/scss/base/_scaffolding.scss
diff --git a/web-ui/public/scss/mixins/_position-helpers.scss b/web-ui/app/scss/mixins/_position-helpers.scss
index 254bfc6c..254bfc6c 100644
--- a/web-ui/public/scss/mixins/_position-helpers.scss
+++ b/web-ui/app/scss/mixins/_position-helpers.scss
diff --git a/web-ui/public/scss/mixins/_tags.scss b/web-ui/app/scss/mixins/_tags.scss
index 9bb287ea..9bb287ea 100644
--- a/web-ui/public/scss/mixins/_tags.scss
+++ b/web-ui/app/scss/mixins/_tags.scss
diff --git a/web-ui/public/scss/sandbox.scss b/web-ui/app/scss/sandbox.scss
index 3c1be358..3c1be358 100644
--- a/web-ui/public/scss/sandbox.scss
+++ b/web-ui/app/scss/sandbox.scss
diff --git a/web-ui/public/scss/style.scss b/web-ui/app/scss/style.scss
index e99ab194..e99ab194 100644
--- a/web-ui/public/scss/style.scss
+++ b/web-ui/app/scss/style.scss
diff --git a/web-ui/public/scss/templates/_no-content-placeholder.scss b/web-ui/app/scss/templates/_no-content-placeholder.scss
index c6807011..c6807011 100644
--- a/web-ui/public/scss/templates/_no-content-placeholder.scss
+++ b/web-ui/app/scss/templates/_no-content-placeholder.scss
diff --git a/web-ui/public/scss/templates/_unread-count.scss b/web-ui/app/scss/templates/_unread-count.scss
index f7852227..f7852227 100644
--- a/web-ui/public/scss/templates/_unread-count.scss
+++ b/web-ui/app/scss/templates/_unread-count.scss
diff --git a/web-ui/public/scss/vendor/_customfont.scss b/web-ui/app/scss/vendor/_customfont.scss
index d72cca0f..d72cca0f 100644
--- a/web-ui/public/scss/vendor/_customfont.scss
+++ b/web-ui/app/scss/vendor/_customfont.scss
diff --git a/web-ui/public/scss/vendor/_foundation.scss b/web-ui/app/scss/vendor/_foundation.scss
index 7918cf26..7918cf26 100644
--- a/web-ui/public/scss/vendor/_foundation.scss
+++ b/web-ui/app/scss/vendor/_foundation.scss
diff --git a/web-ui/public/scss/vendor/_reset.scss b/web-ui/app/scss/vendor/_reset.scss
index 55f8d054..55f8d054 100644
--- a/web-ui/public/scss/vendor/_reset.scss
+++ b/web-ui/app/scss/vendor/_reset.scss
diff --git a/web-ui/public/scss/vendor/_scut.scss b/web-ui/app/scss/vendor/_scut.scss
index 3e16fa65..3e16fa65 100644
--- a/web-ui/public/scss/vendor/_scut.scss
+++ b/web-ui/app/scss/vendor/_scut.scss
diff --git a/web-ui/public/scss/views/_action-bar.scss b/web-ui/app/scss/views/_action-bar.scss
index 40e677b0..40e677b0 100644
--- a/web-ui/public/scss/views/_action-bar.scss
+++ b/web-ui/app/scss/views/_action-bar.scss
diff --git a/web-ui/public/scss/views/_close-button.scss b/web-ui/app/scss/views/_close-button.scss
index 37171c18..37171c18 100644
--- a/web-ui/public/scss/views/_close-button.scss
+++ b/web-ui/app/scss/views/_close-button.scss
diff --git a/web-ui/public/scss/views/_compose-button.scss b/web-ui/app/scss/views/_compose-button.scss
index 81e0bb33..81e0bb33 100644
--- a/web-ui/public/scss/views/_compose-button.scss
+++ b/web-ui/app/scss/views/_compose-button.scss
diff --git a/web-ui/public/scss/views/_compose-view.scss b/web-ui/app/scss/views/_compose-view.scss
index 9e120357..9e120357 100644
--- a/web-ui/public/scss/views/_compose-view.scss
+++ b/web-ui/app/scss/views/_compose-view.scss
diff --git a/web-ui/public/scss/views/_mail-list.scss b/web-ui/app/scss/views/_mail-list.scss
index f5c4c60f..f5c4c60f 100644
--- a/web-ui/public/scss/views/_mail-list.scss
+++ b/web-ui/app/scss/views/_mail-list.scss
diff --git a/web-ui/public/scss/views/_message-panel.scss b/web-ui/app/scss/views/_message-panel.scss
index 4a0a7a6b..4a0a7a6b 100644
--- a/web-ui/public/scss/views/_message-panel.scss
+++ b/web-ui/app/scss/views/_message-panel.scss
diff --git a/web-ui/public/scss/views/_navigation.scss b/web-ui/app/scss/views/_navigation.scss
index 2c33a791..2c33a791 100644
--- a/web-ui/public/scss/views/_navigation.scss
+++ b/web-ui/app/scss/views/_navigation.scss
diff --git a/web-ui/public/scss/views/_no-mails-available.scss b/web-ui/app/scss/views/_no-mails-available.scss
index bf5d256a..bf5d256a 100644
--- a/web-ui/public/scss/views/_no-mails-available.scss
+++ b/web-ui/app/scss/views/_no-mails-available.scss
diff --git a/web-ui/public/scss/views/_no-message-selected.scss b/web-ui/app/scss/views/_no-message-selected.scss
index 0e367bf2..0e367bf2 100644
--- a/web-ui/public/scss/views/_no-message-selected.scss
+++ b/web-ui/app/scss/views/_no-message-selected.scss
diff --git a/web-ui/public/scss/views/_read-view.scss b/web-ui/app/scss/views/_read-view.scss
index f69d51a5..f69d51a5 100644
--- a/web-ui/public/scss/views/_read-view.scss
+++ b/web-ui/app/scss/views/_read-view.scss
diff --git a/web-ui/public/scss/views/_security-labels.scss b/web-ui/app/scss/views/_security-labels.scss
index ac966ded..ac966ded 100644
--- a/web-ui/public/scss/views/_security-labels.scss
+++ b/web-ui/app/scss/views/_security-labels.scss
diff --git a/web-ui/public/templates/compose/attachment_item.hbs b/web-ui/app/templates/compose/attachment_item.hbs
index 7a64f6f5..7a64f6f5 100644
--- a/web-ui/public/templates/compose/attachment_item.hbs
+++ b/web-ui/app/templates/compose/attachment_item.hbs
diff --git a/web-ui/public/templates/compose/attachment_upload_item.hbs b/web-ui/app/templates/compose/attachment_upload_item.hbs
index eb6c4ba6..eb6c4ba6 100644
--- a/web-ui/public/templates/compose/attachment_upload_item.hbs
+++ b/web-ui/app/templates/compose/attachment_upload_item.hbs
diff --git a/web-ui/public/templates/compose/attachments_list.hbs b/web-ui/app/templates/compose/attachments_list.hbs
index 6f34df9e..6f34df9e 100644
--- a/web-ui/public/templates/compose/attachments_list.hbs
+++ b/web-ui/app/templates/compose/attachments_list.hbs
diff --git a/web-ui/public/templates/compose/compose_box.hbs b/web-ui/app/templates/compose/compose_box.hbs
index fcfbeaaf..fcfbeaaf 100644
--- a/web-ui/public/templates/compose/compose_box.hbs
+++ b/web-ui/app/templates/compose/compose_box.hbs
diff --git a/web-ui/public/templates/compose/feedback_box.hbs b/web-ui/app/templates/compose/feedback_box.hbs
index 346a6192..346a6192 100644
--- a/web-ui/public/templates/compose/feedback_box.hbs
+++ b/web-ui/app/templates/compose/feedback_box.hbs
diff --git a/web-ui/public/templates/compose/fixed_recipient.hbs b/web-ui/app/templates/compose/fixed_recipient.hbs
index 8b01717c..8b01717c 100644
--- a/web-ui/public/templates/compose/fixed_recipient.hbs
+++ b/web-ui/app/templates/compose/fixed_recipient.hbs
diff --git a/web-ui/public/templates/compose/inline_box.hbs b/web-ui/app/templates/compose/inline_box.hbs
index c9c114ec..c9c114ec 100644
--- a/web-ui/public/templates/compose/inline_box.hbs
+++ b/web-ui/app/templates/compose/inline_box.hbs
diff --git a/web-ui/public/templates/compose/no_mails_available.hbs b/web-ui/app/templates/compose/no_mails_available.hbs
index c61152a4..c61152a4 100644
--- a/web-ui/public/templates/compose/no_mails_available.hbs
+++ b/web-ui/app/templates/compose/no_mails_available.hbs
diff --git a/web-ui/public/templates/compose/no_message_selected.hbs b/web-ui/app/templates/compose/no_message_selected.hbs
index 0b9beaf8..0b9beaf8 100644
--- a/web-ui/public/templates/compose/no_message_selected.hbs
+++ b/web-ui/app/templates/compose/no_message_selected.hbs
diff --git a/web-ui/public/templates/compose/recipient_input.hbs b/web-ui/app/templates/compose/recipient_input.hbs
index 9416f11f..9416f11f 100644
--- a/web-ui/public/templates/compose/recipient_input.hbs
+++ b/web-ui/app/templates/compose/recipient_input.hbs
diff --git a/web-ui/public/templates/compose/recipients.hbs b/web-ui/app/templates/compose/recipients.hbs
index 43aced1c..43aced1c 100644
--- a/web-ui/public/templates/compose/recipients.hbs
+++ b/web-ui/app/templates/compose/recipients.hbs
diff --git a/web-ui/public/templates/compose/reply_section.hbs b/web-ui/app/templates/compose/reply_section.hbs
index 45203d87..45203d87 100644
--- a/web-ui/public/templates/compose/reply_section.hbs
+++ b/web-ui/app/templates/compose/reply_section.hbs
diff --git a/web-ui/public/templates/compose/upload_attachment_failed.hbs b/web-ui/app/templates/compose/upload_attachment_failed.hbs
index dbb1437b..dbb1437b 100644
--- a/web-ui/public/templates/compose/upload_attachment_failed.hbs
+++ b/web-ui/app/templates/compose/upload_attachment_failed.hbs
diff --git a/web-ui/public/templates/feedback/feedback_trigger.hbs b/web-ui/app/templates/feedback/feedback_trigger.hbs
index 7f3f8ef1..7f3f8ef1 100644
--- a/web-ui/public/templates/feedback/feedback_trigger.hbs
+++ b/web-ui/app/templates/feedback/feedback_trigger.hbs
diff --git a/web-ui/public/templates/mail_actions/actions_box.hbs b/web-ui/app/templates/mail_actions/actions_box.hbs
index 68a8d0bf..68a8d0bf 100644
--- a/web-ui/public/templates/mail_actions/actions_box.hbs
+++ b/web-ui/app/templates/mail_actions/actions_box.hbs
diff --git a/web-ui/public/templates/mail_actions/compose_trigger.hbs b/web-ui/app/templates/mail_actions/compose_trigger.hbs
index 06f05fca..06f05fca 100644
--- a/web-ui/public/templates/mail_actions/compose_trigger.hbs
+++ b/web-ui/app/templates/mail_actions/compose_trigger.hbs
diff --git a/web-ui/public/templates/mail_actions/pagination_trigger.hbs b/web-ui/app/templates/mail_actions/pagination_trigger.hbs
index cbd8a089..cbd8a089 100644
--- a/web-ui/public/templates/mail_actions/pagination_trigger.hbs
+++ b/web-ui/app/templates/mail_actions/pagination_trigger.hbs
diff --git a/web-ui/public/templates/mail_actions/refresh_trigger.hbs b/web-ui/app/templates/mail_actions/refresh_trigger.hbs
index dffc7090..dffc7090 100644
--- a/web-ui/public/templates/mail_actions/refresh_trigger.hbs
+++ b/web-ui/app/templates/mail_actions/refresh_trigger.hbs
diff --git a/web-ui/public/templates/mail_actions/trash_actions_box.hbs b/web-ui/app/templates/mail_actions/trash_actions_box.hbs
index 4e0ec332..4e0ec332 100644
--- a/web-ui/public/templates/mail_actions/trash_actions_box.hbs
+++ b/web-ui/app/templates/mail_actions/trash_actions_box.hbs
diff --git a/web-ui/public/templates/mails/draft.hbs b/web-ui/app/templates/mails/draft.hbs
index 808ce3ff..808ce3ff 100644
--- a/web-ui/public/templates/mails/draft.hbs
+++ b/web-ui/app/templates/mails/draft.hbs
diff --git a/web-ui/public/templates/mails/full_view.hbs b/web-ui/app/templates/mails/full_view.hbs
index 40bfd4a2..40bfd4a2 100644
--- a/web-ui/public/templates/mails/full_view.hbs
+++ b/web-ui/app/templates/mails/full_view.hbs
diff --git a/web-ui/public/templates/mails/mail_actions.hbs b/web-ui/app/templates/mails/mail_actions.hbs
index 0adfe853..0adfe853 100644
--- a/web-ui/public/templates/mails/mail_actions.hbs
+++ b/web-ui/app/templates/mails/mail_actions.hbs
diff --git a/web-ui/public/templates/mails/sent.hbs b/web-ui/app/templates/mails/sent.hbs
index 158b20c8..158b20c8 100644
--- a/web-ui/public/templates/mails/sent.hbs
+++ b/web-ui/app/templates/mails/sent.hbs
diff --git a/web-ui/public/templates/mails/single.hbs b/web-ui/app/templates/mails/single.hbs
index aaede844..aaede844 100644
--- a/web-ui/public/templates/mails/single.hbs
+++ b/web-ui/app/templates/mails/single.hbs
diff --git a/web-ui/public/templates/mails/trash.hbs b/web-ui/app/templates/mails/trash.hbs
index f8947b15..f8947b15 100644
--- a/web-ui/public/templates/mails/trash.hbs
+++ b/web-ui/app/templates/mails/trash.hbs
diff --git a/web-ui/public/templates/page/logout.hbs b/web-ui/app/templates/page/logout.hbs
index 0cc079bc..0cc079bc 100644
--- a/web-ui/public/templates/page/logout.hbs
+++ b/web-ui/app/templates/page/logout.hbs
diff --git a/web-ui/public/templates/page/logout_shortcut.hbs b/web-ui/app/templates/page/logout_shortcut.hbs
index 043ab0dc..043ab0dc 100644
--- a/web-ui/public/templates/page/logout_shortcut.hbs
+++ b/web-ui/app/templates/page/logout_shortcut.hbs
diff --git a/web-ui/public/templates/page/user_settings_box.hbs b/web-ui/app/templates/page/user_settings_box.hbs
index 2152b779..2152b779 100644
--- a/web-ui/public/templates/page/user_settings_box.hbs
+++ b/web-ui/app/templates/page/user_settings_box.hbs
diff --git a/web-ui/public/templates/page/user_settings_icon.hbs b/web-ui/app/templates/page/user_settings_icon.hbs
index 8f2f9215..8f2f9215 100644
--- a/web-ui/public/templates/page/user_settings_icon.hbs
+++ b/web-ui/app/templates/page/user_settings_icon.hbs
diff --git a/web-ui/public/templates/page/version.hbs b/web-ui/app/templates/page/version.hbs
index 5f43f78a..5f43f78a 100644
--- a/web-ui/public/templates/page/version.hbs
+++ b/web-ui/app/templates/page/version.hbs
diff --git a/web-ui/public/templates/search/search_trigger.hbs b/web-ui/app/templates/search/search_trigger.hbs
index 2261d154..2261d154 100644
--- a/web-ui/public/templates/search/search_trigger.hbs
+++ b/web-ui/app/templates/search/search_trigger.hbs
diff --git a/web-ui/public/templates/tags/shortcut.hbs b/web-ui/app/templates/tags/shortcut.hbs
index 1e82d6a9..1e82d6a9 100644
--- a/web-ui/public/templates/tags/shortcut.hbs
+++ b/web-ui/app/templates/tags/shortcut.hbs
diff --git a/web-ui/public/templates/tags/tag.hbs b/web-ui/app/templates/tags/tag.hbs
index ca397b9a..ca397b9a 100644
--- a/web-ui/public/templates/tags/tag.hbs
+++ b/web-ui/app/templates/tags/tag.hbs
diff --git a/web-ui/public/templates/tags/tag_inner.hbs b/web-ui/app/templates/tags/tag_inner.hbs
index 2e0958cb..2e0958cb 100644
--- a/web-ui/public/templates/tags/tag_inner.hbs
+++ b/web-ui/app/templates/tags/tag_inner.hbs
diff --git a/web-ui/public/templates/tags/tag_list.hbs b/web-ui/app/templates/tags/tag_list.hbs
index 92a73283..92a73283 100644
--- a/web-ui/public/templates/tags/tag_list.hbs
+++ b/web-ui/app/templates/tags/tag_list.hbs
diff --git a/web-ui/public/templates/user_alerts/message.hbs b/web-ui/app/templates/user_alerts/message.hbs
index abba1f91..abba1f91 100644
--- a/web-ui/public/templates/user_alerts/message.hbs
+++ b/web-ui/app/templates/user_alerts/message.hbs
diff --git a/web-ui/config/add_git_version.sh b/web-ui/config/add_git_version.sh
index abda150a..a0abefc0 100755
--- a/web-ui/config/add_git_version.sh
+++ b/web-ui/config/add_git_version.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-TEMPLATE_FILE="public/js/generated/hbs/templates.js"
+TEMPLATE_FILE="app/js/generated/hbs/templates.js"
COMMITISH=$(git rev-parse --short HEAD)
COMMITDATE=$(git show -s --format=%cd)
diff --git a/web-ui/config/buildoptions.js b/web-ui/config/buildoptions.js
index 2e7ba028..63c91653 100644
--- a/web-ui/config/buildoptions.js
+++ b/web-ui/config/buildoptions.js
@@ -16,11 +16,11 @@
*/
({
- baseUrl: '../public',
+ baseUrl: '../app',
wrap: true,
almond: true,
optimize: 'none',
- mainConfigFile: '../public/js/main.js',
+ mainConfigFile: '../app/js/main.js',
out: '../.tmp/app.concatenated.js',
include: ['js/main'],
name: 'bower_components/almond/almond'
diff --git a/web-ui/config/compass.rb b/web-ui/config/compass.rb
index 461bd9e2..9c52a04e 100644
--- a/web-ui/config/compass.rb
+++ b/web-ui/config/compass.rb
@@ -17,12 +17,14 @@
# Set this to the root of your project when deployed:
+target_dir = ENV['PIXELATED_BUILD'] == 'package' ? 'dist' : 'app'
+
+
http_path = "/"
-css_dir = "public/css"
-sass_dir = "public/scss"
-images_dir = "src/images"
-generated_images_dir = "public/images"
-javascripts_dir = "public/js"
+css_dir = "#{target_dir}/css"
+sass_dir = "app/scss"
+images_dir = "app/images"
+javascripts_dir = "app/js"
# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
diff --git a/web-ui/config/control-tower.yml b/web-ui/config/control-tower.yml
index 2d4d5865..874e1b64 100644
--- a/web-ui/config/control-tower.yml
+++ b/web-ui/config/control-tower.yml
@@ -1,3 +1,3 @@
---
-include_pattern: 'public/js/**/*.js'
+include_pattern: 'app/js/**/*.js'
exclude_pattern: ''
diff --git a/web-ui/config/imagemin.js b/web-ui/config/imagemin.js
index 6f94373e..2b2c87e0 100644
--- a/web-ui/config/imagemin.js
+++ b/web-ui/config/imagemin.js
@@ -17,8 +17,8 @@
const imagemin = require('imagemin');
-imagemin(['src/images/*.{gif,jpg,png,svg}'],
- 'public/images'
+imagemin(['app/images/*.{gif,jpg,png,svg}'],
+ 'dist/images'
).then(files => {
console.log('Images list:')
files.map(function(file) { console.log(file.path); });
diff --git a/web-ui/config/minify_app.sh b/web-ui/config/minify_app.sh
deleted file mode 100644
index d9e232a5..00000000
--- a/web-ui/config/minify_app.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2014 ThoughtWorks, Inc.
-#
-# Pixelated is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# Pixelated is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
-
-set -e
-
-# concat js files and minify for app.min.js
-cat \
-public/bower_components/modernizr/modernizr.js \
-public/bower_components/lodash/dist/lodash.js \
-public/bower_components/jquery/dist/jquery.js \
-public/bower_components/jquery-ui/jquery-ui.js \
-public/bower_components/jquery-file-upload/js/jquery.fileupload.js \
-public/js/lib/highlightRegex.js \
-public/bower_components/handlebars/handlebars.js \
-public/bower_components/typeahead.js/dist/typeahead.bundle.js \
-public/bower_components/foundation/js/foundation.js \
-public/bower_components/foundation/js/foundation/foundation.reveal.js \
-public/bower_components/foundation/js/foundation/foundation.offcanvas.js \
-public/js/foundation/initialize_foundation.js \
-public/bower_components/iframe-resizer/js/iframeResizer.js \
-.tmp/app.concatenated.js | node_modules/.bin/minify --js > public/app.min.js
diff --git a/web-ui/config/package.sh b/web-ui/config/package.sh
index 06351257..165eeff3 100644
--- a/web-ui/config/package.sh
+++ b/web-ui/config/package.sh
@@ -18,11 +18,61 @@
set -e
+export PIXELATED_BUILD='package'
+
+mkdir -p dist
+
# initial npm tasks
-./go build
+./go clean
+./go compass
+./go handlebars
+./go imagemin
+./go minify_html
+./go minify_sandbox
+./go add_git_version
+./go buildmain
+
-if [ ! -s public/app.min.js ]
+# copy files
+cd app
+cp --parents \
+404.html \
+fonts/* \
+locales/**/* \
+bower_components/font-awesome/css/font-awesome.min.css \
+bower_components/jquery-file-upload/css/jquery.fileupload.css \
+bower_components/font-awesome/fonts/* \
+../dist
+cd -
+
+# concat js files and minify for app.min.js
+cat \
+app/bower_components/modernizr/modernizr.js \
+app/bower_components/lodash/dist/lodash.js \
+app/bower_components/jquery/dist/jquery.js \
+app/bower_components/jquery-ui/jquery-ui.js \
+app/bower_components/jquery-file-upload/js/jquery.fileupload.js \
+app/js/lib/highlightRegex.js \
+app/bower_components/handlebars/handlebars.js \
+app/bower_components/typeahead.js/dist/typeahead.bundle.js \
+app/bower_components/foundation/js/foundation.js \
+app/bower_components/foundation/js/foundation/foundation.reveal.js \
+app/bower_components/foundation/js/foundation/foundation.offcanvas.js \
+app/js/foundation/initialize_foundation.js \
+app/bower_components/iframe-resizer/js/iframeResizer.js \
+.tmp/app.concatenated.js > dist/app.js
+node_modules/.bin/minify dist/app.js > dist/app.min.js
+rm dist/app.js
+
+if [ ! -s dist/app.min.js ]
then
echo "Minification failed!"
exit 1;
fi
+
+# concat js files and minify for sandbox.min.js
+cat \
+app/js/sandbox.js \
+app/bower_components/iframe-resizer/js/iframeResizer.contentWindow.js > dist/sandbox.js
+node_modules/.bin/minify dist/sandbox.js > dist/sandbox.min.js
+rm dist/sandbox.js
diff --git a/web-ui/karma.conf.js b/web-ui/karma.conf.js
index 93628052..52b54f57 100644
--- a/web-ui/karma.conf.js
+++ b/web-ui/karma.conf.js
@@ -17,51 +17,51 @@ module.exports = function (config) {
// list of files / patterns to load in the browser
files: [
// loaded without require
- 'public/bower_components/lodash/dist/lodash.js',
- 'public/bower_components/jquery/dist/jquery.js',
- 'public/bower_components/jquery-ui/jquery-ui.min.js',
- 'public/bower_components/jquery-file-upload/js/jquery.fileupload.js',
- 'public/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
- 'public/bower_components/jasmine-flight/lib/jasmine-flight.js',
- 'public/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
- 'public/bower_components/handlebars/handlebars.min.js',
- 'public/bower_components/modernizr/modernizr.js',
- 'public/bower_components/foundation/js/foundation.js',
- 'public/bower_components/foundation/js/foundation/foundation.reveal.js',
- 'public/bower_components/foundation/js/foundation/foundation.offcanvas.js',
- 'public/js/lib/highlightRegex.js',
+ 'app/bower_components/lodash/dist/lodash.js',
+ 'app/bower_components/jquery/dist/jquery.js',
+ 'app/bower_components/jquery-ui/jquery-ui.min.js',
+ 'app/bower_components/jquery-file-upload/js/jquery.fileupload.js',
+ 'app/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
+ 'app/bower_components/jasmine-flight/lib/jasmine-flight.js',
+ 'app/bower_components/jasmine-jquery/lib/jasmine-jquery.js',
+ 'app/bower_components/handlebars/handlebars.min.js',
+ 'app/bower_components/modernizr/modernizr.js',
+ 'app/bower_components/foundation/js/foundation.js',
+ 'app/bower_components/foundation/js/foundation/foundation.reveal.js',
+ 'app/bower_components/foundation/js/foundation/foundation.offcanvas.js',
+ 'app/js/lib/highlightRegex.js',
// hack to load RequireJS after the shim libs
'node_modules/requirejs/require.js',
'node_modules/karma-requirejs/lib/adapter.js',
// loaded with require
- {pattern: 'public/bower_components/DOMPurify/dist/purify.min.js', included: false},
- {pattern: 'public/bower_components/he/he.js', included: false},
- {pattern: 'public/bower_components/flight/**/*.js', included: false},
- {pattern: 'public/bower_components/i18next/**/*.js', included: false},
- {pattern: 'public/bower_components/i18next-xhr-backend/**/*.js', included: false},
- {pattern: 'public/bower_components/i18next-browser-languagedetector/**/*.js', included: false},
- {pattern: 'public/bower_components/quoted-printable/*.js', included: false},
- {pattern: 'public/bower_components/utf8/utf8.js', included: false},
- {pattern: 'public/locales/**/*.json', included: false},
- {pattern: 'public/js/**/*.js', included: false},
+ {pattern: 'app/bower_components/DOMPurify/dist/purify.min.js', included: false},
+ {pattern: 'app/bower_components/he/he.js', included: false},
+ {pattern: 'app/bower_components/flight/**/*.js', included: false},
+ {pattern: 'app/bower_components/i18next/**/*.js', included: false},
+ {pattern: 'app/bower_components/i18next-xhr-backend/**/*.js', included: false},
+ {pattern: 'app/bower_components/i18next-browser-languagedetector/**/*.js', included: false},
+ {pattern: 'app/bower_components/quoted-printable/*.js', included: false},
+ {pattern: 'app/bower_components/utf8/utf8.js', included: false},
+ {pattern: 'app/locales/**/*.json', included: false},
+ {pattern: 'app/js/**/*.js', included: false},
{pattern: 'test/test_data.js', included: false},
{pattern: 'test/custom_matchers.js', included: false},
{pattern: 'test/features.js', included: false},
{pattern: 'test/spec/**/*.spec.js', included: false},
- {pattern: 'public/sandbox.html', included: true, served: true},
+ {pattern: 'app/sandbox.html', included: true, served: true},
'test/test-main.js'
],
proxies: {
- '/sandbox/sandbox.html': '/base/public/sandbox.html',
+ '/sandbox/sandbox.html': '/base/app/sandbox.html',
},
// list of files to exclude
exclude: [
- 'public/js/main.js'
+ 'app/js/main.js'
],
// test results reporter to use
@@ -69,7 +69,7 @@ module.exports = function (config) {
reporters: ['dots', 'junit', 'coverage'],
preprocessors: {
- 'public/js/!(lib)/**/*.js': ['coverage']
+ 'app/js/!(lib)/**/*.js': ['coverage']
},
// enable / disable watching file and executing tests whenever any file changes
diff --git a/web-ui/package.json b/web-ui/package.json
index 83931b09..2a0056e4 100644
--- a/web-ui/package.json
+++ b/web-ui/package.json
@@ -5,23 +5,20 @@
"repository": "https://github.com/pixelated-project/pixelated-user-agent",
"private": true,
"devDependencies": {
- "babel": "^6.5.2",
- "babel-cli": "^6.18.0",
"bower": "1.7.9",
- "browserify": "^13.1.1",
"handlebars": "4.0.5",
"html-minifier": "2.1.6",
"imagemin": "5.2.1",
"jshint": "2.9.2",
"karma": "0.13.19",
"karma-chrome-launcher": "0.2.2",
- "karma-coverage": "0.2.7",
"karma-firefox-launcher": "0.1.7",
"karma-jasmine": "0.2.2",
"karma-jasmine-ajax": "0.1.13",
"karma-junit-reporter": "0.2.2",
"karma-phantomjs-launcher": "1.0.1",
"karma-requirejs": "1.0.0",
+ "karma-coverage": "0.2.7",
"minify": "2.0.9",
"requirejs": "2.2.0",
"watch": "0.19.1"
@@ -31,34 +28,18 @@
"debug": "npm run build && node_modules/karma/bin/karma start --browsers Chrome $GRUNT_OPTS",
"watch": "npm run compass-watch & npm run handlebars-watch",
"watch-test": "node_modules/karma/bin/karma start",
- "handlebars": "mkdir -p public/js/generated/hbs/ && node_modules/handlebars/bin/handlebars public/templates/**/*.hbs > public/js/generated/hbs/templates.js --namespace=window.Pixelated --root .",
- "handlebars-watch": "node_modules/.bin/watch 'npm run handlebars' public/templates",
+ "handlebars": "mkdir -p app/js/generated/hbs/ && node_modules/handlebars/bin/handlebars app/templates/**/*.hbs > app/js/generated/hbs/templates.js --namespace=window.Pixelated --root .",
+ "handlebars-watch": "node_modules/.bin/watch 'npm run handlebars' app/templates",
"compass": "compass compile",
"compass-watch": "compass watch",
- "build": "npm run clean && npm run handlebars && npm run add_git_version && npm run compass && npm run imagemin && npm run build-signup && npm run buildmain && npm run minify_app && npm run minify_sandbox",
- "build-signup": "babel src/js -d lib/js && browserify lib/js/index.js >public/signup.js",
- "jshint": "node_modules/jshint/bin/jshint --config=.jshintrc src public test",
- "clean": "rm -rf .tmp/ public/js/generated/hbs/* public/css/* lib/js public/signup.js",
+ "build": "npm run clean && npm run handlebars && npm run add_git_version && npm run compass",
+ "jshint": "node_modules/jshint/bin/jshint --config=.jshintrc app test",
+ "clean": "rm -rf .tmp/ 'dist/*' app/js/generated/hbs/* app/css/*",
"buildmain": "node_modules/requirejs/bin/r.js -o config/buildoptions.js",
- "minify_app": "/bin/bash config/minify_app.sh",
- "minify_sandbox": "cat public/js/sandbox.js public/bower_components/iframe-resizer/js/iframeResizer.contentWindow.js | node_modules/.bin/minify --js > public/sandbox.min.js",
"package": "/bin/bash config/package.sh",
"imagemin": "node config/imagemin.js",
+ "minify_html": "node_modules/.bin/html-minifier app/index.html --collapse-whitespace | sed 's|<!--usemin_start-->.*<!--usemin_end-->|<script src=\"assets/app.min.js\" type=\"text/javascript\"></script>|' > dist/index.html",
+ "minify_sandbox": "node_modules/.bin/html-minifier app/sandbox.html --collapse-whitespace | sed 's|<!--usemin_start-->.*<!--usemin_end-->|<script src=\"sandbox.min.js\" type=\"text/javascript\"></script>|' > dist/sandbox.html",
"add_git_version": "/bin/bash config/add_git_version.sh"
- },
- "dependencies": {
- "babel-preset-es2015": "^6.18.0",
- "babel-preset-react": "^6.16.0",
- "immutable": "^3.8.1",
- "react": "^15.3.2",
- "react-dom": "^15.3.2",
- "redux": "^3.6.0",
- "whatwg-fetch": "^2.0.0"
- },
- "babel": {
- "presets": [
- "es2015",
- "react"
- ]
}
}
diff --git a/web-ui/public/dummy.json b/web-ui/public/dummy.json
deleted file mode 100644
index 0967ef42..00000000
--- a/web-ui/public/dummy.json
+++ /dev/null
@@ -1 +0,0 @@
-{}
diff --git a/web-ui/public/js/views/templates.js b/web-ui/public/js/views/templates.js
deleted file mode 100644
index 8792f8cb..00000000
--- a/web-ui/public/js/views/templates.js
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2014 ThoughtWorks, Inc.
- *
- * Pixelated is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Pixelated is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
- */
-
-define(['hbs/templates'], function (templates) {
- 'use strict';
-
- var Templates = {
- compose: {
- box: window.Pixelated['public/templates/compose/compose_box.hbs'],
- inlineBox: window.Pixelated['public/templates/compose/inline_box.hbs'],
- replySection: window.Pixelated['public/templates/compose/reply_section.hbs'],
- recipientInput: window.Pixelated['public/templates/compose/recipient_input.hbs'],
- fixedRecipient: window.Pixelated['public/templates/compose/fixed_recipient.hbs'],
- recipients: window.Pixelated['public/templates/compose/recipients.hbs'],
- feedback: window.Pixelated['public/templates/compose/feedback_box.hbs'],
- attachmentsList: window.Pixelated['public/templates/compose/attachments_list.hbs'],
- attachmentItem: window.Pixelated['public/templates/compose/attachment_item.hbs'],
- attachmentUploadItem: window.Pixelated['public/templates/compose/attachment_upload_item.hbs'],
- uploadAttachmentFailed: window.Pixelated['public/templates/compose/upload_attachment_failed.hbs']
- },
- tags: {
- tagList: window.Pixelated['public/templates/tags/tag_list.hbs'],
- tag: window.Pixelated['public/templates/tags/tag.hbs'],
- tagInner: window.Pixelated['public/templates/tags/tag_inner.hbs'],
- shortcut: window.Pixelated['public/templates/tags/shortcut.hbs']
- },
- userAlerts: {
- message: window.Pixelated['public/templates/user_alerts/message.hbs']
- },
- mails: {
- single: window.Pixelated['public/templates/mails/single.hbs'],
- fullView: window.Pixelated['public/templates/mails/full_view.hbs'],
- mailActions: window.Pixelated['public/templates/mails/mail_actions.hbs'],
- draft: window.Pixelated['public/templates/mails/draft.hbs'],
- sent: window.Pixelated['public/templates/mails/sent.hbs'],
- trash: window.Pixelated['public/templates/mails/trash.hbs']
- },
- mailActions: {
- actionsBox: window.Pixelated['public/templates/mail_actions/actions_box.hbs'],
- trashActionsBox: window.Pixelated['public/templates/mail_actions/trash_actions_box.hbs'],
- composeTrigger: window.Pixelated['public/templates/mail_actions/compose_trigger.hbs'],
- refreshTrigger: window.Pixelated['public/templates/mail_actions/refresh_trigger.hbs'],
- paginationTrigger: window.Pixelated['public/templates/mail_actions/pagination_trigger.hbs']
- },
- noMessageSelected: window.Pixelated['public/templates/compose/no_message_selected.hbs'],
- noMailsAvailable: window.Pixelated['public/templates/compose/no_mails_available.hbs'],
- search: {
- trigger: window.Pixelated['public/templates/search/search_trigger.hbs']
- },
- page: {
- userSettingsIcon: window.Pixelated['public/templates/page/user_settings_icon.hbs'],
- userSettingsBox: window.Pixelated['public/templates/page/user_settings_box.hbs'],
- logout: window.Pixelated['public/templates/page/logout.hbs'],
- logoutShortcut: window.Pixelated['public/templates/page/logout_shortcut.hbs'],
- version: window.Pixelated['public/templates/page/version.hbs']
- },
- feedback: {
- feedback: window.Pixelated['public/templates/feedback/feedback_trigger.hbs']
- }
- };
-
- Handlebars.registerPartial('tag_inner', Templates.tags.tagInner);
- Handlebars.registerPartial('recipients', Templates.compose.recipients);
- Handlebars.registerPartial('attachments_list', Templates.compose.attachmentsList);
- Handlebars.registerPartial('attachments_upload', Templates.compose.attachmentsList);
- Handlebars.registerPartial('attachment_item', Templates.compose.attachmentItem);
- Handlebars.registerPartial('attachment_upload_item', Templates.compose.attachmentUploadItem);
- Handlebars.registerPartial('uploadAttachmentFailed', Templates.compose.uploadAttachmentFailed);
-
- return Templates;
-});
diff --git a/web-ui/public/sandbox.html b/web-ui/public/sandbox.html
deleted file mode 100644
index d24a8452..00000000
--- a/web-ui/public/sandbox.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html>
-
-<head>
- <meta charset="utf-8">
- <link href="css/sandbox.css" rel="stylesheet" type="text/css">
-
- <script src="sandbox.min.js" type="text/javascript"></script>
-</head>
-
-<body></body>
-
-</html>
diff --git a/web-ui/public/signup.css b/web-ui/public/signup.css
deleted file mode 100644
index 61ac8587..00000000
--- a/web-ui/public/signup.css
+++ /dev/null
@@ -1,174 +0,0 @@
-body {
- font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif;
-}
-
-.field-group {
- position:relative;
- margin-bottom: 35px;
-}
-
-label {
- font-size: 0.9em;
- margin-bottom: 10px;
- display: inline-block;
-}
-
-input {
- display: block;
- border: solid 1px #4da3b6;
- width: 100%;
- height: auto;
- padding: 10px 5px;
- margin-bottom: 20px;
-}
-
-.animated-label {
- color:#999;
- position:absolute;
- pointer-events:none;
- left: 6px;
- top:10px;
- transition:0.2s ease all;
- -moz-transition:0.2s ease all;
- -webkit-transition:0.2s ease all;
-}
-
-input:focus {
- outline:none;
-}
-
-input:focus ~ .animated-label, input:valid ~ .animated-label{
- top:-20px;
- left: 0;
- font-size:0.8em;
- color:#4da3b6;
-}
-
-.blue-button {
- background: #178ca6;
- color: white;
- display: block;
- text-decoration: none;
- text-align: center;
- padding: 10px 0 10px 0;
- width: 104%;
- margin: 0 auto;
-}
-
-.blue-button:hover {
- background: #4da3b6;
-}
-
-a {
- text-decoration: none;
- color: #4da3b6;
-}
-
-h1 {
- font-size: 1.5em;
- text-align: center;
-}
-
-header {
- width: 18%;
- margin: 0 auto;
-}
-
-.link-message {
- text-align: center;
- font-size: 0.8em;
-}
-
-.logo {
- width: 100%;
- height: auto;
- padding-top: 20%;
- margin-bottom: 30px;
-}
-
-.message h1 {
- margin-bottom: 35px;
-}
-
-.message p {
- padding-left: 5%;
- padding-right: 5%;
- width: 40%;
- margin: 0 auto;
- text-align: center;
- line-height: 1.8em;
- font-size: 0.9em;
-}
-
-.form-container {
- width: 20%;
- margin: 0 auto;
- padding-top: 40px;
-}
-
-.domain-label {
- position: relative;
- top: 26px;
- padding-left: 20px;
- left: 100%;
-}
-
-.sent-email-icon {
- width: 60px;
-}
-
-.disabled {
- pointer-events: none;
- background: #d4d4d4;
-}
-
-.link-message .disabled {
- pointer-events: none;
- color: #d4d4d4;
- background: none;
-}
-
-/* Medium Devices, Desktops */
-@media only screen and (max-width : 992px) {
- header {
- width: 20%;
- }
-
- .form-container {
- width: 30%;
- }
-
- .message p {
- width: 70%
- }
-}
-
-/* Small Devices, Tablets */
-@media only screen and (max-width : 768px) {
- header {
- width: 30%;
- }
-
- .form-container {
- width: 50%;
- }
-
- .message p {
- width: 80%
- }
-}
-
-/* Extra Small Devices, Phones */
-@media only screen and (max-width : 480px) {
- header {
- width: 60%;
- }
-
- .form-container {
- width: 80%;
- }
-
- .message p {
- width: 85%
- }
-}
diff --git a/web-ui/public/signup.html b/web-ui/public/signup.html
deleted file mode 100644
index 9814f585..00000000
--- a/web-ui/public/signup.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="utf-8">
- <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
- <title>Pixelated Mail</title>
- <meta name="description" content="">
- <meta name="viewport" content="width=device-width">
- <link rel="stylesheet" type="text/css" href="/static/normalize.min.css" />
- <link rel="stylesheet" type="text/css" href="/static/signup.css" />
- </head>
- <body>
- <header><img src="/static/images/pixelated-logo-orange.svg" alt="Pixelated" class="logo"/></header>
- <div class="message">
- <div id="app"></div>
- <script src="/static/signup.js"></script>
- </div>
- </body>
-</html>
diff --git a/web-ui/src/images/pixelated-logo-orange.svg b/web-ui/src/images/pixelated-logo-orange.svg
deleted file mode 100644
index 7e0ef43d..00000000
--- a/web-ui/src/images/pixelated-logo-orange.svg
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- width="509.707px" height="142.439px" viewBox="0 0 509.707 142.439" enable-background="new 0 0 509.707 142.439"
- xml:space="preserve">
-<g>
- <path fill="#F9A731" d="M0,35.469v71.365l62.837,35.605l62.833-35.605V35.469L62.813,0L0,35.469z M60.262,116.617L23.735,96.332
- V52.46l36.586,20.999L60.262,116.617z M101.936,96.332l-36.148,20.285l0.067-43.123l36.081-21.034V96.332z M101.936,46.44
- L62.951,69.553L23.733,46.44l39.218-21.131L101.936,46.44z"/>
- <path fill="#F9A731" d="M169.505,42.332h-19.968v59.328h13.52V79.655h6.448c11.579,0,20.279-6.832,20.279-19.056
- C189.784,48.302,181.084,42.332,169.505,42.332z M166.866,68.868h-3.809v-15.75h3.809c5.323,0,10.357,1.798,10.357,7.91
- C177.224,67.07,172.189,68.868,166.866,68.868z"/>
- <rect x="194.309" y="42.332" fill="#F9A731" width="13.52" height="59.328"/>
- <polygon fill="#F9A731" points="266.516,42.332 249.689,42.332 238.759,58.514 227.827,42.332 211.721,42.332 230.417,69.73
- 210.228,101.66 226.982,101.66 238.759,81.453 250.534,101.66 268.01,101.66 247.099,69.73 "/>
- <polygon fill="#F9A731" points="270.128,101.66 304.069,101.66 304.069,89.795 283.647,89.795 283.647,77.857 303.207,77.857
- 303.207,65.991 283.647,65.991 283.647,54.199 304.069,54.199 304.069,42.332 270.128,42.332 "/>
- <path fill="#F9A731" d="M354.807,42.332l-19.156,47.463H322.33V42.332h-13.52v59.328h22.053h11.888h2.636l4.386-11.865h22.578
- l4.391,11.865h14.524l-23.944-59.328H354.807z M354.377,77.928l6.614-17.257h0.145l6.615,17.257H354.377z"/>
- <polygon fill="#F9A731" points="379.939,54.199 394.073,54.199 394.073,101.66 407.592,101.66 407.592,54.199 421.687,54.199
- 421.687,42.332 379.939,42.332 "/>
- <polygon fill="#F9A731" points="426.265,101.66 460.207,101.66 460.207,89.795 439.785,89.795 439.785,77.857 459.344,77.857
- 459.344,65.991 439.785,65.991 439.785,54.199 460.207,54.199 460.207,42.332 426.265,42.332 "/>
- <path fill="#F9A731" d="M479.792,42.332h-14.94v59.328h14.94c16.324,0,29.914-12.37,29.914-29.699
- C509.707,54.701,496.044,42.332,479.792,42.332z M480.457,89.577h-2.084V54.414h2.084c10.067,0,16.9,7.695,16.9,17.619
- C497.285,81.955,490.455,89.577,480.457,89.577z"/>
-</g>
-</svg>
diff --git a/web-ui/src/images/sent_email.png b/web-ui/src/images/sent_email.png
deleted file mode 100644
index ddaa11d0..00000000
--- a/web-ui/src/images/sent_email.png
+++ /dev/null
Binary files differ
diff --git a/web-ui/src/js/index.js b/web-ui/src/js/index.js
deleted file mode 100644
index 8e66db06..00000000
--- a/web-ui/src/js/index.js
+++ /dev/null
@@ -1,235 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import {createStore} from 'redux';
-import {Map} from 'immutable';
-import 'whatwg-fetch';
-
-
-class PixelatedComponent extends React.Component {
- _updateStateFromStore() {
- this.setState(this.props.store.getState().toJS());
- }
-
- componentWillMount() {
- this.unsubscribe = this.props.store.subscribe(() => this._updateStateFromStore());
- this._updateStateFromStore();
- }
-
- componentWillUnmount() {
- this.unsubscribe();
- }
-}
-
-
-class PixelatedForm extends PixelatedComponent {
- _fetchAndDispatch(url, actionProperties) {
- const immutableActionProperties = new Map(actionProperties);
- this.props.store.dispatch(immutableActionProperties.merge({status: 'STARTED'}).toJS());
- fetch(url).then((response) => {
- return response.json();
- }).then((json) => {
- setTimeout(() => {
- this.props.store.dispatch(immutableActionProperties.merge({status: 'SUCCESS', json: json}).toJS());
- }, 3000);
- }).catch((error) => {
- console.error('something went wrong', error);
- this.props.store.dispatch(immutableActionProperties.merge({status: 'ERROR', error: error}).toJS());
- });
- }
-}
-
-
-class InviteCodeForm extends PixelatedForm {
- render() {
- let className = "blue-button validation-link";
-
- if(!this.state.inviteCodeValidation) {
- className = className + " disabled";
- }
-
- return (
- <form onSubmit={this._handleClick.bind(this)}>
- <div className="field-group">
- <input type="text" name="invite-code" className="invite-code" onChange={this._handleInputEmpty.bind(this)} required/>
- <label className="animated-label" htmlFor="invite-code">invite code</label>
- </div>
- <input type="submit" value="Get Started" className={className} />
- </form>
- );
- }
-
- _handleClick(event) {
- event.stopPropagation();
- event.preventDefault();
- this.props.store.dispatch({type: 'SUBMIT_INVITE_CODE', inviteCode: event.target['invite-code'].value});
- }
-
- _handleInputEmpty(event) {
- this.props.store.dispatch({type: 'VALIDATE_INVITE_CODE', inviteCode: event.target.value});
- }
-}
-
-
-class CreateAccountForm extends PixelatedForm {
- render() {
- return (
- <form onSubmit={this._handleClick.bind(this)}>
- <span className="domain-label"> @domain.com </span>
- <div className="field-group">
- <input type="text" name="username" className="username" required/>
- <label className="animated-label" htmlFor="username">username</label>
- </div>
-
- <div className="field-group">
- <input type="password" name="password" className="password" required/>
- <label className="animated-label" htmlFor="password">password</label>
- </div>
-
- <input type="submit" value="Create my account" className="blue-button validation-link" />
- </form>
- );
- }
-
- _handleClick(event) {
- event.stopPropagation();
- event.preventDefault();
- this.props.store.dispatch({type: 'SUBMIT_CREATE_ACCOUNT', username: event.target.username.value, password: event.target.password.value});
- }
-}
-
-
-class BackupEmailForm extends PixelatedForm {
- render() {
- return (
- <form onSubmit={this._handleClick.bind(this)}>
- <div className="field-group">
- <input type="text" name="backup-email" required/>
- <label className="animated-label" htmlFor="password">type your backup email</label>
- </div>
-
- <input type="submit" value="Send Email" className="blue-button validation-link" />
- <p className="link-message">
- <a href="#" className="validation-link">I didn't receive anything. Send the email again</a>
- </p>
- </form>
- );
- }
-
- _handleClick(event) {
- event.stopPropagation();
- event.preventDefault();
- this._fetchAndDispatch('dummy.json', {type: 'SUBMIT_BACKUP_EMAIL', backupEmail: event.target['backup-email'].value});
- }
-}
-
-
-class BackupEmailSentForm extends PixelatedForm {
- render() {
- return (
- <form onSubmit={this._handleClick.bind(this)}>
- {this.state.isFetching || <a href="/" className="blue-button">I received the codes. <br/>Go to my inbox</a>}
- <p className="link-message">
- <a href="#">I didn't receive anything. Send the email again</a>
- </p>
- </form>
- );
- }
-
- _handleClick(event) {
- event.stopPropagation();
- event.preventDefault();
- }
-}
-
-
-class SignUp extends PixelatedComponent {
- render() {
- return (
- <div>
- <div className="message">
- <h1>{this.state.header}</h1>
- {this.state.icon}
- <p>{this.state.summary}</p>
- </div>
- <div className="form-container">
- {this._form()}
- </div>
- </div>
- );
- }
-
- _form() {
- switch(this.state.form) {
- case 'invite_code': return <InviteCodeForm store={store} />;
- case 'create_account': return <CreateAccountForm store={store} />;
- case 'backup_email': return <BackupEmailForm store={store} />;
- case 'backup_email_sent': return <BackupEmailSentForm store={store} />;
- default: throw Error('TODO');
- }
- }
-}
-
-
-const initialState = new Map({
- isFetching: false,
- form: 'invite_code',
- header: 'Welcome',
- icon: null,
- summary: ['Do you have an invite code?', <br key='br1' />, 'Type it below'],
-});
-
-
-const store = createStore((state=initialState, action) => {
- switch (action.type) {
- case 'SUBMIT_INVITE_CODE':
- return state.merge({
- inviteCode: action.inviteCode,
- form: 'create_account',
- header: 'Create your account',
- summary: 'Choose your username, and be careful about your password, it must be strong and easy to remember. If you have a password manager, we strongly advise you to use one.',
- });
- case 'SUBMIT_CREATE_ACCOUNT':
- return state.merge({
- username: action.username,
- password: action.password,
- form: 'backup_email',
- header: 'In case you lose your password...',
- summary: 'Set up a backup email account. You\'ll receive an email with a code so you can recover your account in the future, other will be sent to your account administrator.',
- });
- case 'SUBMIT_BACKUP_EMAIL':
- switch (action.status) {
- case 'STARTED':
- return state.merge({
- isFetching: true,
- backupEmail: action.backupEmail,
- form: 'backup_email_sent',
- icon: <p><img key="img1" src="images/sent_email.png" className="sent-email-icon"/></p>,
- summary: 'An email was sent to the email you provided. Check your spam folder, just in case.',
- });
- case 'SUCCESS':
- return state.merge({
- isFetching: false,
- });
- case 'ERROR':
- return state.merge({
- isFetching: false,
- });
- default:
- return state;
- }
- case 'SUBMIT_BACKUP_EMAIL_SENT':
- return state.merge({});
- case 'VALIDATE_INVITE_CODE':
- return state.merge({
- inviteCodeValidation: Boolean(action.inviteCode)
- });
- default:
- return state;
- }
-});
-
-
-ReactDOM.render(
- <SignUp store={store}/>,
- document.getElementById('app')
-);
diff --git a/web-ui/test/test-main.js b/web-ui/test/test-main.js
index ce76be9b..4396993f 100644
--- a/web-ui/test/test-main.js
+++ b/web-ui/test/test-main.js
@@ -19,34 +19,34 @@ requirejs.config({
baseUrl: '/base',
paths: {
- 'page': 'public/js/page',
- 'js': 'public/js',
- 'lib': 'public/js/lib',
- 'hbs': 'public/js/generated/hbs',
- 'flight': 'public/bower_components/flight',
- 'DOMPurify': 'public/bower_components/DOMPurify/dist/purify.min',
- 'he': 'public/bower_components/he/he',
- 'views': 'public/js/views',
- 'helpers': 'public/js/helpers',
- 'feedback': 'public/js/feedback',
- 'tags': 'public/js/tags',
- 'mail_list': 'public/js/mail_list',
- 'mail_list_actions': 'public/js/mail_list_actions',
- 'user_alerts': 'public/js/user_alerts',
- 'mail_view': 'public/js/mail_view',
- 'dispatchers': 'public/js/dispatchers',
- 'mixins': 'public/js/mixins',
- 'services': 'public/js/services',
- 'search': 'public/js/search',
- 'monkey_patching': 'public/js/monkey_patching',
- 'i18next': 'public/bower_components/i18next/i18next',
- 'i18nextXHRBackend': 'public/bower_components/i18next-xhr-backend/i18nextXHRBackend',
- 'i18nextBrowserLanguageDetector': 'public/bower_components/i18next-browser-languagedetector/i18nextBrowserLanguageDetector',
- 'quoted-printable': 'public/bower_components/quoted-printable',
- 'utf8': 'public/bower_components/utf8',
+ 'page': 'app/js/page',
+ 'js': 'app/js',
+ 'lib': 'app/js/lib',
+ 'hbs': 'app/js/generated/hbs',
+ 'flight': 'app/bower_components/flight',
+ 'DOMPurify': 'app/bower_components/DOMPurify/dist/purify.min',
+ 'he': 'app/bower_components/he/he',
+ 'views': 'app/js/views',
+ 'helpers': 'app/js/helpers',
+ 'feedback': 'app/js/feedback',
+ 'tags': 'app/js/tags',
+ 'mail_list': 'app/js/mail_list',
+ 'mail_list_actions': 'app/js/mail_list_actions',
+ 'user_alerts': 'app/js/user_alerts',
+ 'mail_view': 'app/js/mail_view',
+ 'dispatchers': 'app/js/dispatchers',
+ 'mixins': 'app/js/mixins',
+ 'services': 'app/js/services',
+ 'search': 'app/js/search',
+ 'monkey_patching': 'app/js/monkey_patching',
+ 'i18next': 'app/bower_components/i18next/i18next',
+ 'i18nextXHRBackend': 'app/bower_components/i18next-xhr-backend/i18nextXHRBackend',
+ 'i18nextBrowserLanguageDetector': 'app/bower_components/i18next-browser-languagedetector/i18nextBrowserLanguageDetector',
+ 'quoted-printable': 'app/bower_components/quoted-printable',
+ 'utf8': 'app/bower_components/utf8',
'test': 'test',
'features': 'test/features',
- 'user_settings': 'public/js/user_settings'
+ 'user_settings': 'app/js/user_settings'
},
deps: tests,
@@ -73,7 +73,7 @@ requirejs.config({
.init({
lng: 'en_US',
backend: {
- loadPath: '/base/public/locales/en_US/translation.json'
+ loadPath: '/base/app/locales/en_US/translation.json'
}
});
Handlebars.registerHelper('t', i18n.t);