Skip to content
This repository
Browse code

Comitted first public revision of Solace. Development history from the

internal SVN was dropped for security reasons.
  • Loading branch information...
commit 0acfd9e704626bc32273ca15e85e9867b3917a44 0 parents
Armin Ronacher authored

Showing 113 changed files with 23,136 additions and 0 deletions. Show diff stats Hide diff stats

  1. +8 0 .hgignore
  2. +21 0 AUTHORS
  3. +185 0 HACKING
  4. +31 0 LICENSE
  5. +170 0 README
  6. BIN  artwork/arrows.psd
  7. +495 0 artwork/recycle.svg
  8. BIN  artwork/tick.psd
  9. +73 0 setup.py
  10. +14 0 solace/__init__.py
  11. +413 0 solace/application.py
  12. +231 0 solace/auth.py
  13. +223 0 solace/badges.py
  14. +371 0 solace/database.py
  15. +258 0 solace/forms.py
  16. +255 0 solace/i18n/__init__.py
  17. +1 0  solace/i18n/de/LC_MESSAGES/messages.js
  18. BIN  solace/i18n/de/LC_MESSAGES/messages.mo
  19. +1,214 0 solace/i18n/de/LC_MESSAGES/messages.po
  20. +1,097 0 solace/i18n/messages.pot
  21. +967 0 solace/models.py
  22. +27 0 solace/packs.py
  23. +385 0 solace/scripts.py
  24. +190 0 solace/settings.py
  25. BIN  solace/static/arrows.png
  26. BIN  solace/static/arrows_gray.png
  27. +160 0 solace/static/babel.js
  28. BIN  solace/static/badge_earned.png
  29. BIN  solace/static/badge_not_earned.png
  30. +65 0 solace/static/badges.css
  31. BIN  solace/static/badges/critic.png
  32. BIN  solace/static/badges/editor.png
  33. BIN  solace/static/badges/good_answer.png
  34. BIN  solace/static/badges/great_answer.png
  35. BIN  solace/static/badges/inquirer.png
  36. BIN  solace/static/badges/nice_answer.png
  37. BIN  solace/static/badges/reversal.png
  38. BIN  solace/static/badges/self_critic.png
  39. BIN  solace/static/badges/self_learner.png
  40. BIN  solace/static/badges/troubleshooter.png
  41. BIN  solace/static/badges/unique_answer.png
  42. +272 0 solace/static/creole.js
  43. BIN  solace/static/feed.png
  44. BIN  solace/static/flashtick.png
  45. +10 0 solace/static/ie.css
  46. +9 0 solace/static/ie6.css
  47. +759 0 solace/static/jquery.autocomplete.js
  48. +643 0 solace/static/jquery.form.js
  49. +4,376 0 solace/static/jquery.js
  50. +1,188 0 solace/static/layout.css
  51. BIN  solace/static/recycle.png
  52. BIN  solace/static/recycle_big.png
  53. +472 0 solace/static/solace.js
  54. +234 0 solace/static/teal.css
  55. BIN  solace/static/tick.png
  56. BIN  solace/static/tick_gray.png
  57. +28 0 solace/templates/_helpers.html
  58. +15 0 solace/templates/api/debug_dump.html
  59. +106 0 solace/templates/api/help.html
  60. +30 0 solace/templates/badges/show_badge.html
  61. +21 0 solace/templates/badges/show_list.html
  62. +8 0 solace/templates/core/about.html
  63. +23 0 solace/templates/core/login.html
  64. +10 0 solace/templates/core/no_javascript.html
  65. +7 0 solace/templates/core/not_found.html
  66. +12 0 solace/templates/core/register.html
  67. +24 0 solace/templates/core/reset_password.html
  68. +168 0 solace/templates/kb/_boxes.html
  69. +12 0 solace/templates/kb/_comments.html
  70. +28 0 solace/templates/kb/_editor.html
  71. +22 0 solace/templates/kb/by_tag.html
  72. +17 0 solace/templates/kb/delete_post.html
  73. +26 0 solace/templates/kb/edit_post.html
  74. +14 0 solace/templates/kb/new.html
  75. +19 0 solace/templates/kb/overview.html
  76. +36 0 solace/templates/kb/post_revisions.html
  77. +28 0 solace/templates/kb/restore_post.html
  78. +23 0 solace/templates/kb/sections.html
  79. +18 0 solace/templates/kb/tags.html
  80. +47 0 solace/templates/kb/topic.html
  81. +19 0 solace/templates/kb/unanswered.html
  82. +90 0 solace/templates/layout.html
  83. +13 0 solace/templates/mails/activate_user.txt
  84. +6 0 solace/templates/mails/layout.txt
  85. +12 0 solace/templates/mails/reset_password.txt
  86. +12 0 solace/templates/users/edit_profile.html
  87. +76 0 solace/templates/users/profile.html
  88. +37 0 solace/templates/users/userlist.html
  89. +59 0 solace/templating.py
  90. +112 0 solace/tests/__init__.py
  91. +126 0 solace/tests/core_views.py
  92. +124 0 solace/tests/kb_views.py
  93. +215 0 solace/tests/models.py
  94. +84 0 solace/tests/querycount.py
  95. +96 0 solace/urls.py
  96. +10 0 solace/utils/__init__.py
  97. +2,348 0 solace/utils/_translit_tab.py
  98. +184 0 solace/utils/api.py
  99. +26 0 solace/utils/ctxlocal.py
  100. +268 0 solace/utils/formatting.py
  101. +1,859 0 solace/utils/forms.py
  102. +115 0 solace/utils/lazystring.py
  103. +147 0 solace/utils/mail.py
  104. +96 0 solace/utils/pagination.py
  105. +82 0 solace/utils/recaptcha.py
  106. +77 0 solace/utils/remoting.py
  107. +257 0 solace/utils/support.py
  108. +10 0 solace/views/__init__.py
  109. +124 0 solace/views/api.py
  110. +35 0 solace/views/badges.py
  111. +204 0 solace/views/core.py
  112. +565 0 solace/views/kb.py
  113. +89 0 solace/views/users.py
8 .hgignore
... ... @@ -0,0 +1,8 @@
  1 +\.py[oc]$
  2 +\.DS_Store$
  3 +^dist/
  4 +\.egg$
  5 +\.log$
  6 +\.cfg$
  7 +^env/
  8 +\.egg-info$
21 AUTHORS
... ... @@ -0,0 +1,21 @@
  1 +Solace is written and maintained by the Plurk Inc. and various contributors.
  2 +
  3 +Development Lead:
  4 +
  5 +- Armin Ronacher <armin.ronacher@active-4.com>
  6 +
  7 +Some parts of the code are taken from existing projects:
  8 +
  9 + From the Zine blogging platform:
  10 +
  11 + - solace.utils.forms
  12 + - solace.utils.mail
  13 + - solace.i18n
  14 +
  15 + From the Sphinx documentation tool:
  16 +
  17 + - solace.scripts
  18 +
  19 + From Jason Kirtland's translit tab:
  20 +
  21 + - solace.utils._translit_tab
185 HACKING
... ... @@ -0,0 +1,185 @@
  1 +
  2 +
  3 + // HACKING ON SOLACE //
  4 +
  5 + ~ HACKING ~
  6 +
  7 + Hacking on Solace is fun. It's written in Python and based
  8 + on pupular libraries. The dynamic parts in the user interface
  9 + are created using HTML 4 and jQuery.
  10 +
  11 + This file should give you a brief overview how the code works
  12 + and what you should keep in mind when working on it.
  13 +
  14 + ~ STYLEGUIDE ~
  15 +
  16 + Solace follows PEP 8 for Python code. The rule you should
  17 + follow is "adapt to the code style used in the file". And
  18 + that also means, put whitespace where the original author
  19 + put it and so on.
  20 +
  21 + Indent with 4 *spaces* only.
  22 +
  23 + JavaScript code is intended with 2 spaces and only two spaces.
  24 + The same rule applies for HTML as well.
  25 +
  26 + **Every page has to validate against HTML 4.01 transitional**.
  27 +
  28 + If you need features HTML 4 does not give you, use JavaScript!
  29 + We're using the transitional DTD because recaptcha uses iframes
  30 + for non-JavaScript enabled browsers.
  31 +
  32 + We will probably switch to HTML 5 once support is widespread
  33 + but until then, the doctype has to be HTML 4.01 transitional.
  34 + The reason for this rule is that many browser validators such as
  35 + the firefox validator plugin does not support HTML 5 yet which
  36 + makes it nearly impossible to ensure that every page validates.
  37 +
  38 + CSS spacing rules should follow the existing rules in the files.
  39 + Use whitespace after property, value colons.
  40 +
  41 + CSS files *have* to use relative paths, so do templates. A
  42 + template should use `url_for` where possible. The application
  43 + does not enforce itself to be mounted on the URL root, so assume
  44 + it can be anywhere.
  45 +
  46 + CSS classes are lowercase and use underscore for separation.
  47 +
  48 + All filenames have to be lowercase and ASCII only.
  49 +
  50 + ~ URLS ~
  51 +
  52 + Rules for URLs are simple. Stuff that depends on a language and
  53 + is *publically* available is mounted below `/<lang_code>`.
  54 +
  55 + Stuff invoked by JavaScript, that redirects back or is remotely
  56 + JavaScript related has a leading underscore.
  57 +
  58 + Examples:
  59 +
  60 + /login
  61 + /<lang_code>/
  62 + /_set_timezone
  63 + /_vote/<post>
  64 +
  65 + ~ INTERFACE GUIDELINES ~
  66 +
  67 + The Solace user interface is intended to be used by everybody
  68 + not just hackers. Keep that in mind when working on the code
  69 + base.
  70 +
  71 + // Emphasis //
  72 +
  73 + The emphasis is always on the non-technical elements. For
  74 + example in the overview page the emphasis is on the title,
  75 + number of votes and replies, but not on the tags. Tags are
  76 + elements not everybody is familiar with.
  77 +
  78 + // Font Sizes //
  79 +
  80 + The following font sizes are in use:
  81 +
  82 + 10px preferred bold and only for navigation, errors
  83 + and popup menus.
  84 + 11px for meta information such as authors etc.
  85 + 13px for regular text
  86 + 20px for headline like content such as questions on
  87 + the overview page.
  88 + 24px the biggest headline and in caps the header
  89 +
  90 + Special font sizes
  91 +
  92 + 18px used by the hinted editor. As long as a field is
  93 + empty it may display a 18px big and #69A9B8 colored
  94 + text instead.
  95 +
  96 + // Margins & Padding //
  97 +
  98 + Standard margins 10px
  99 + above header, below footer 50px
  100 + small separation 3px 7px
  101 +
  102 + // Colors //
  103 +
  104 + Use the following colors for the CSS:
  105 +
  106 + #2a606d standard link color, darkish blue
  107 + #0E3640 very dark blue, nav background
  108 + (combine with white) or marked text
  109 + #458696 popup background
  110 + #C2DDE3 blue box background
  111 + #E1EDF0 tag background
  112 + #EEF8FA editor background
  113 +
  114 + #69A9B8 hint text color
  115 + #B5DDE6 editor border color
  116 +
  117 + #FAFAFA preview boxes, deleted content
  118 + #eee inactive elements, headline background
  119 + #ccc boxes on deleted content
  120 + #555 text on deleted content
  121 +
  122 + #A8DFAA background for inserted text
  123 + #FDF5F5 background for deleted text
  124 + #EB4040 color for deleted text
  125 + #F5F2D7 background for modified text
  126 +
  127 + // Client-side Scripting //
  128 +
  129 + The core functionality of Solace should work without
  130 + JavaScript on modern browsers. (We do not consider either
  131 + IE6 or IE7 as modern browser).
  132 +
  133 + Currently the only feature that does not work without
  134 + JavaScript is adding comments to questions and replies.
  135 +
  136 + Whenever you cannot provide a non-javascript implementation
  137 + of a feature, make sure that the user somehow ends up on
  138 + the special `_no_javascript` page. Either on click or
  139 + somehow else. That one tells the user to enable JavaScript
  140 + to use this feature.
  141 +
  142 + // Language Handling //
  143 +
  144 + Solace has two indepdendent language context. The language
  145 + of the UI and the language of the section the user is active
  146 + in.
  147 +
  148 + Sometimes the user leaves a section in which case the links
  149 + that point back to a section (in the navigation bar) will
  150 + point to the section of the UI language. Whenever that
  151 + happens the link that points to that section has to be marked
  152 + with the faded color so that the user knows the link might
  153 + not take him back to where he came from. At the same time
  154 + the link to the active section disappears.
  155 +
  156 + You can try that by clicking on the "badges" link. The
  157 + "ask" and other buttons will be slightly faded out.
  158 +
  159 + If you're adding new pages, keep that behavior in mind.
  160 +
  161 + ~ TEMPLATES ~
  162 +
  163 + Templates must not contain any CSS information besides classes.
  164 + Use classes as appropriate, and use as many of them as you like.
  165 + Keep them easy to read.
  166 +
  167 + Use macros to ensure that you are using the same elements and
  168 + classes for the same widget (tags, users, badges etc.)
  169 +
  170 + ~ UNIT TESTS ~
  171 +
  172 + Solace uses standard Python unittests for all tests. You can use
  173 + doctest as well if you convert it into a unittest testsuite
  174 + using the `doctest.DocTestSuite`.
  175 +
  176 + In general what you have to do is to add a test to one of the
  177 + existing test modules (`solace.tests.module`) and make sure that
  178 + you either add the test to an existing suite or add a new suite
  179 + and register it in the `suite` factory function.
  180 +
  181 + If you add a full new module to the test module, also open the
  182 + `tests` package's `__init__` file and make sure your suite is
  183 + added properly.
  184 +
  185 + To run the tests you can use `python setup.py test`.
31 LICENSE
... ... @@ -0,0 +1,31 @@
  1 +Copyright (c) 2009 by the Solace Team, see AUTHORS for more details.
  2 +
  3 +Some rights reserved.
  4 +
  5 +Redistribution and use in source and binary forms, with or without
  6 +modification, are permitted provided that the following conditions are
  7 +met:
  8 +
  9 + * Redistributions of source code must retain the above copyright
  10 + notice, this list of conditions and the following disclaimer.
  11 +
  12 + * Redistributions in binary form must reproduce the above
  13 + copyright notice, this list of conditions and the following
  14 + disclaimer in the documentation and/or other materials provided
  15 + with the distribution.
  16 +
  17 + * The names of the contributors may not be used to endorse or
  18 + promote products derived from this software without specific
  19 + prior written permission.
  20 +
  21 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
170 README
... ... @@ -0,0 +1,170 @@
  1 +
  2 +
  3 + // SOLACE //
  4 +
  5 + ~ a multilingual support system ~
  6 +
  7 +
  8 + ~ INTRODUCTION ~
  9 +
  10 + Solace is a multilingual support system developed at Plurk
  11 + for end user support. The application design is heavily
  12 + influenced by bulletin boards like phpBB and the new
  13 + stackoverflow programming community site.
  14 +
  15 + ~ INSTALLING ~
  16 +
  17 + For a four-step quickstart have a look at the end of the
  18 + file. It explains how to quickly test Solace on your
  19 + local box.
  20 +
  21 + Solace is developed in Python as a standard conforming WSGI
  22 + application with the help of the following libraries:
  23 +
  24 + - Werkzeug
  25 + - Jinja2
  26 + - SQLAlchemy
  27 + - Babel
  28 + - creoleparser
  29 + - simplejson
  30 + - webdepcompress
  31 +
  32 + If you want to hack on Solace on your own the best way to get
  33 + started is using the all-mygthy `setup.py` script in a virtual
  34 + Python environment.
  35 +
  36 + If you're not familiar with virtualenv, be sure to have it
  37 + installed and run it like this in the solace folder:
  38 +
  39 + $ virtualenv env
  40 +
  41 + Aferwards you can activate it. On linux or OS X you can use
  42 + the following command:
  43 +
  44 + $ source env/bin/activate
  45 +
  46 + If you're working on a Windows box, use the activate batch
  47 + file instead:
  48 +
  49 + $ env\Scripts\activate.bat
  50 +
  51 + After you have activated the environment you can use the
  52 + `develop` command from the setup script to start working on
  53 + Solace:
  54 +
  55 + $ python setup.py develop
  56 +
  57 + If you want to install it into a virtual environment (or
  58 + system wide, which we however do not recommend) you can use
  59 + the `install` command
  60 +
  61 + $ python setup.py install
  62 +
  63 + Both `develop` and `install` will take care of dependencies
  64 + for you.
  65 +
  66 + ~ THE CONFIGURATION ~
  67 +
  68 + Where does Solace get the settings from? It comes with some
  69 + default settings that unless overridden will be the ones it
  70 + uses. The defaults are intended for development purposes only
  71 + have *have to be changed* if you want to use Solace in
  72 + production.
  73 +
  74 + WHen Solace initializes it checks for a `SOLACE_SETTINGS_FILE`
  75 + environment variable. If it finds one, it will execute the
  76 + file set as a Python script and overrides the assigned variables
  77 + in that script in the config.
  78 +
  79 + Example configuration:
  80 +
  81 + DATABASE_URI = 'mysql://root@localhost/my_database'
  82 + SECRET_KEY = 'a-super-secret-and-random-key'
  83 +
  84 + ~ SERVER SETUP ~
  85 +
  86 + As mentioned before Solace is a WSGI application. The WSGI
  87 + application object is know as `solace.application.application`.
  88 + For example if you want to use `mod_wsgi` all you have to do
  89 + is to create a `solace.wsgi` file with the following contents:
  90 +
  91 + from solace.application import application
  92 +
  93 + This however would require that the `SOLACE_SETTINGS_FILE`
  94 + variable is set in the server config. If you don't want to
  95 + do that, you can also set it in the `.wsgi` file or tell
  96 + the settings system to load the config from a file:
  97 +
  98 + from solace import settings
  99 + settings.configure_from_file('/var/www/solace/solace.cfg')
  100 + from solace.application import application
  101 +
  102 + Be sure to use absolute paths for the configuration!
  103 +
  104 + ~ LOCAL TEST SERVER ~
  105 +
  106 + If you want to test Solace locally or hack on it, you can use
  107 + the `runserver` command of the setup script:
  108 +
  109 + $ python setup.py runserver
  110 +
  111 + This will start a development server on `localhost:3000`.
  112 +
  113 + ~ DATABASE INITIALIZATION ~
  114 +
  115 + Solace uses a database for testing. Currently the following
  116 + database systems are supported:
  117 +
  118 + - sqlite3
  119 + - MySQL
  120 + - Postgres
  121 +
  122 + We recommend sqlite3 for testing (which incidentally is the
  123 + defualt) and Postgres for production.
  124 +
  125 + To initialize the database make sure to have the database
  126 + URI set in a config, the `SOLACE_SETTINGS_FILE` environment
  127 + variable exported and then run the following command:
  128 +
  129 + $ python setup.py initdb
  130 +
  131 + This will create the database tables for you.
  132 +
  133 + If you also want a administrator user to be created you
  134 + can sue the `reset` command instead:
  135 +
  136 + $ python setup.py reset
  137 +
  138 + This is especially handy during development.
  139 +
  140 + ~ TESTING ~
  141 +
  142 + Solace is using standard Python unittests which you can run
  143 + from the `setup.py` script
  144 +
  145 + $ python setup.py test
  146 +
  147 + If you want to fill the database with data for testing you can
  148 + use the setup script as well:
  149 +
  150 + $ python setup.py make_testdata
  151 +
  152 + Warning on tests: For tests make sure to have a newer version
  153 + than 0.5.1 in your venv (at the time of this writing this means
  154 + installing a development version) due to a bug in the redirect
  155 + support and path quoting of the test client in 0.5.1.
  156 +
  157 + ~ QUICKSTART ~
  158 +
  159 + - make sure to have virtualenv installed
  160 + - run "virtualenv env" in the folder that contains this file.
  161 + - depending on your operating system run:
  162 + Windows: "env\Scripts\activate.bat"
  163 + Linux / OS X: "source env/bin/activate"
  164 + - run "python setup.py develop"
  165 + - run "python setup.py reset"
  166 + - run "python setup.py runserver"
  167 +
  168 + The server will then run on `localhost:3000`. The database
  169 + is stored in a temporary folder unless you provide a config.
  170 + This is fine for development and testing.
BIN  artwork/arrows.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
495 artwork/recycle.svg
... ... @@ -0,0 +1,495 @@
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
  3 +<svg
  4 + xmlns:i="&amp;ns_ai;"
  5 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  6 + xmlns:cc="http://creativecommons.org/ns#"
  7 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  8 + xmlns:svg="http://www.w3.org/2000/svg"
  9 + xmlns="http://www.w3.org/2000/svg"
  10 + xmlns:xlink="http://www.w3.org/1999/xlink"
  11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  13 + width="48"
  14 + height="48"
  15 + id="svg57"
  16 + sodipodi:version="0.32"
  17 + inkscape:version="0.46"
  18 + sodipodi:docbase="/home/tigert/cvs/freedesktop.org/tango-icon-theme/scalable/mimetypes"
  19 + sodipodi:docname="recycle.svg"
  20 + inkscape:output_extension="org.inkscape.output.svg.inkscape"
  21 + version="1.0"
  22 + inkscape:export-filename="/Users/mitsuhiko/Development/plurk/solace/solace/static/recycle.png"
  23 + inkscape:export-xdpi="90"
  24 + inkscape:export-ydpi="90">
  25 + <defs
  26 + id="defs3">
  27 + <inkscape:perspective
  28 + sodipodi:type="inkscape:persp3d"
  29 + inkscape:vp_x="0 : 24 : 1"
  30 + inkscape:vp_y="0 : 1000 : 0"
  31 + inkscape:vp_z="48 : 24 : 1"
  32 + inkscape:persp3d-origin="24 : 16 : 1"
  33 + id="perspective47146" />
  34 + <linearGradient
  35 + id="linearGradient381"
  36 + inkscape:collect="always">
  37 + <stop
  38 + id="stop382"
  39 + offset="0"
  40 + style="stop-color:#ffffff;stop-opacity:1;" />
  41 + <stop
  42 + id="stop383"
  43 + offset="1"
  44 + style="stop-color:#ffffff;stop-opacity:0;" />
  45 + </linearGradient>
  46 + <linearGradient
  47 + id="linearGradient368">
  48 + <stop
  49 + style="stop-color:#ffffff;stop-opacity:0.10309278;"
  50 + offset="0.0000000"
  51 + id="stop369" />
  52 + <stop
  53 + style="stop-color:#ffffff;stop-opacity:0.0000000;"
  54 + offset="1.0000000"
  55 + id="stop372" />
  56 + </linearGradient>
  57 + <linearGradient
  58 + id="linearGradient1065">
  59 + <stop
  60 + style="stop-color:#b5c051;stop-opacity:1.0000000;"
  61 + offset="0.0000000"
  62 + id="stop1066" />
  63 + <stop
  64 + style="stop-color:#858e3f;stop-opacity:1.0000000;"
  65 + offset="1.0000000"
  66 + id="stop1067" />
  67 + </linearGradient>
  68 + <linearGradient
  69 + y2="72.608902"
  70 + x2="192.3857"
  71 + y1="72.608902"
  72 + x1="78.245598"
  73 + gradientUnits="userSpaceOnUse"
  74 + id="linearGradient641">
  75 + <stop
  76 + id="stop642"
  77 + style="stop-color:#f9feff;stop-opacity:1.0000000;"
  78 + offset="0.0000000" />
  79 + <stop
  80 + id="stop643"
  81 + style="stop-color:#afb4b6;stop-opacity:1.0000000;"
  82 + offset="1.0000000" />
  83 + </linearGradient>
  84 + <linearGradient
  85 + y2="137.97153"
  86 + x2="136.9856"
  87 + y1="67.364906"
  88 + x1="81.307533"
  89 + gradientTransform="scale(1.244363,0.803624)"
  90 + gradientUnits="userSpaceOnUse"
  91 + id="linearGradient234"
  92 + xlink:href="#linearGradient177"
  93 + inkscape:collect="always" />
  94 + <linearGradient
  95 + id="linearGradient513">
  96 + <stop
  97 + id="stop514"
  98 + offset="0.0000000"
  99 + style="stop-color:#696969;stop-opacity:1.0000000;" />
  100 + <stop
  101 + id="stop515"
  102 + offset="1.0000000"
  103 + style="stop-color:#ffffff;stop-opacity:1.0000000;" />
  104 + </linearGradient>
  105 + <linearGradient
  106 + id="linearGradient508">
  107 + <stop
  108 + id="stop509"
  109 + offset="0.0000000"
  110 + style="stop-color:#b0b0b0;stop-opacity:1.0000000;" />
  111 + <stop
  112 + id="stop510"
  113 + offset="1.0000000"
  114 + style="stop-color:#b0b0b0;stop-opacity:1.0000000;" />
  115 + </linearGradient>
  116 + <linearGradient
  117 + y2="72.608902"
  118 + x2="192.3857"
  119 + y1="72.608902"
  120 + x1="78.245598"
  121 + gradientUnits="userSpaceOnUse"
  122 + id="linearGradient477">
  123 + <stop
  124 + id="stop478"
  125 + style="stop-color:#e4e9ea;stop-opacity:1.0000000;"
  126 + offset="0.0000000" />
  127 + <stop
  128 + id="stop479"
  129 + style="stop-color:#85898A;fill-rule:nonzero;"
  130 + offset="1" />
  131 + </linearGradient>
  132 + <linearGradient
  133 + id="linearGradient454">
  134 + <stop
  135 + id="stop455"
  136 + offset="0.0000000"
  137 + style="stop-color:#ffffff;stop-opacity:1.0000000;" />
  138 + <stop
  139 + id="stop457"
  140 + offset="0.50000000"
  141 + style="stop-color:#bebebe;stop-opacity:1.0000000;" />
  142 + <stop
  143 + id="stop456"
  144 + offset="1.0000000"
  145 + style="stop-color:#b0b0b0;stop-opacity:1.0000000;" />
  146 + </linearGradient>
  147 + <linearGradient
  148 + id="linearGradient177">
  149 + <stop
  150 + id="stop178"
  151 + offset="0.0000000"
  152 + style="stop-color:#ffffff;stop-opacity:1.0000000;" />
  153 + <stop
  154 + id="stop179"
  155 + offset="1.0000000"
  156 + style="stop-color:#b0b0b0;stop-opacity:1.0000000;" />
  157 + </linearGradient>
  158 + <linearGradient
  159 + id="linearGradient172">
  160 + <stop
  161 + id="stop173"
  162 + offset="0.0000000"
  163 + style="stop-color:#616c08;stop-opacity:1.0000000;" />
  164 + <stop
  165 + id="stop174"
  166 + offset="1.0000000"
  167 + style="stop-color:#495106;stop-opacity:1.0000000;" />
  168 + </linearGradient>
  169 + <linearGradient
  170 + id="linearGradient161">
  171 + <stop
  172 + id="stop162"
  173 + offset="0.0000000"
  174 + style="stop-color:#575955;stop-opacity:1.0000000;" />
  175 + <stop
  176 + id="stop163"
  177 + offset="1.0000000"
  178 + style="stop-color:#7c7e79;stop-opacity:1.0000000;" />
  179 + </linearGradient>
  180 + <linearGradient
  181 + id="linearGradient157">
  182 + <stop
  183 + id="stop158"
  184 + offset="0.0000000"
  185 + style="stop-color:#babdb6;stop-opacity:1.0000000;" />
  186 + <stop
  187 + id="stop159"
  188 + offset="1.0000000"
  189 + style="stop-color:#f1f5ec;stop-opacity:1.0000000;" />
  190 + </linearGradient>
  191 + <linearGradient
  192 + id="linearGradient149"
  193 + inkscape:collect="always">
  194 + <stop
  195 + id="stop150"
  196 + offset="0"
  197 + style="stop-color:#000000;stop-opacity:1;" />
  198 + <stop
  199 + id="stop151"
  200 + offset="1"
  201 + style="stop-color:#000000;stop-opacity:0;" />
  202 + </linearGradient>
  203 + <linearGradient
  204 + id="linearGradient1869">
  205 + <stop
  206 + style="stop-color:#eff3f4;stop-opacity:1.0000000;"
  207 + offset="0.0000000"
  208 + id="stop1870" />
  209 + <stop
  210 + style="stop-color:#939596;stop-opacity:1.0000000;"
  211 + offset="1.0000000"
  212 + id="stop1871" />
  213 + </linearGradient>
  214 + <linearGradient
  215 + inkscape:collect="always"
  216 + xlink:href="#linearGradient1869"
  217 + id="linearGradient1872"
  218 + gradientTransform="matrix(1.464893,0,0,0.475906,30.56501,-34.34268)"
  219 + x1="-4.6375198"
  220 + y1="104.38752"
  221 + x2="-4.523921"
  222 + y2="110.61378"
  223 + gradientUnits="userSpaceOnUse" />
  224 + <linearGradient
  225 + gradientUnits="userSpaceOnUse"
  226 + y2="69.460503"
  227 + x2="7.5291119"
  228 + y1="27.376621"
  229 + x1="7.3738608"
  230 + gradientTransform="matrix(3.495016,0,0,0.344323,-2.972087,-3.408148e-2)"
  231 + id="linearGradient152"
  232 + xlink:href="#linearGradient149"
  233 + inkscape:collect="always" />
  234 + <linearGradient
  235 + gradientUnits="userSpaceOnUse"
  236 + y2="6.8897982"
  237 + x2="60.685902"
  238 + y1="6.8897982"
  239 + x1="55.208271"
  240 + gradientTransform="matrix(0.772488,0,0,1.55784,-2.79531,-0.166664)"
  241 + id="linearGradient160"
  242 + xlink:href="#linearGradient157"
  243 + inkscape:collect="always" />
  244 + <radialGradient
  245 + r="5.6434927"
  246 + fy="20.45278"
  247 + fx="16.280994"
  248 + cy="20.45278"
  249 + cx="16.280994"
  250 + gradientTransform="matrix(2.202254,0,0,0.574568,-13.83631,0.652472)"
  251 + gradientUnits="userSpaceOnUse"
  252 + id="radialGradient605"
  253 + xlink:href="#linearGradient477"
  254 + inkscape:collect="always" />
  255 + <linearGradient
  256 + y2="14.74888"
  257 + x2="18.086929"
  258 + y1="11.165159"
  259 + x1="14.248631"
  260 + gradientTransform="matrix(1.399756,0,0,0.903977,-3.99312,0.7519)"
  261 + gradientUnits="userSpaceOnUse"
  262 + id="linearGradient606"
  263 + xlink:href="#linearGradient454"
  264 + inkscape:collect="always" />
  265 + <linearGradient
  266 + y2="122.61145"
  267 + x2="132.98843"
  268 + y1="116.66409"
  269 + x1="128.35213"
  270 + gradientTransform="scale(1.244363,0.803624)"
  271 + gradientUnits="userSpaceOnUse"
  272 + id="linearGradient607"
  273 + xlink:href="#linearGradient177"
  274 + inkscape:collect="always" />
  275 + <linearGradient
  276 + y2="14.744809"
  277 + x2="20.135639"
  278 + y1="8.7251825"
  279 + x1="9.9626188"
  280 + gradientTransform="matrix(1.399756,0,0,0.903977,-3.99312,0.797381)"
  281 + gradientUnits="userSpaceOnUse"
  282 + id="linearGradient608"
  283 + xlink:href="#linearGradient177"
  284 + inkscape:collect="always" />
  285 + <linearGradient
  286 + y2="10.115389"
  287 + x2="40.437176"
  288 + y1="2.3488793"
  289 + x1="24.162909"
  290 + gradientTransform="matrix(1.124876,0,0,1.124876,-3.99312,0.7519)"
  291 + gradientUnits="userSpaceOnUse"
  292 + id="linearGradient609"
  293 + xlink:href="#linearGradient477"
  294 + inkscape:collect="always" />
  295 + <linearGradient
  296 + y2="24.077389"
  297 + x2="-36.301399"
  298 + y1="18.817307"
  299 + x1="-32.400455"
  300 + gradientTransform="matrix(-1.449414,0.286552,-0.469381,0.965804,-2.70059,0.453616)"
  301 + gradientUnits="userSpaceOnUse"
  302 + id="linearGradient610"
  303 + xlink:href="#linearGradient513"
  304 + inkscape:collect="always" />
  305 + <linearGradient
  306 + y2="20.664473"
  307 + x2="45.130928"
  308 + y1="13.131673"
  309 + x1="36.155384"
  310 + gradientTransform="matrix(0.82649,0.763061,0.763061,-0.82649,-30.95946,-9.495656)"
  311 + gradientUnits="userSpaceOnUse"
  312 + id="linearGradient611"
  313 + xlink:href="#linearGradient477"
  314 + inkscape:collect="always" />
  315 + <linearGradient
  316 + y2="9.3615303"
  317 + x2="13.763388"
  318 + y1="14.035932"
  319 + x1="16.551964"
  320 + gradientTransform="matrix(1.399756,0,0,0.903977,-2.86035,0.227876)"
  321 + gradientUnits="userSpaceOnUse"
  322 + id="linearGradient612"
  323 + xlink:href="#linearGradient177"
  324 + inkscape:collect="always" />
  325 + <linearGradient
  326 + y2="14.744809"
  327 + x2="20.135639"
  328 + y1="8.7251825"
  329 + x1="9.9626188"
  330 + gradientTransform="matrix(1.027326,-0.134612,0.528454,0.53648,8.12216,4.8634)"
  331 + gradientUnits="userSpaceOnUse"
  332 + id="linearGradient613"
  333 + xlink:href="#linearGradient508"
  334 + inkscape:collect="always" />
  335 + <linearGradient
  336 + y2="137.97153"
  337 + x2="136.9856"
  338 + y1="67.364906"
  339 + x1="81.307533"
  340 + gradientTransform="scale(1.244363,0.803624)"
  341 + gradientUnits="userSpaceOnUse"
  342 + id="linearGradient632"
  343 + xlink:href="#linearGradient177"
  344 + inkscape:collect="always" />
  345 + <radialGradient
  346 + gradientUnits="userSpaceOnUse"
  347 + r="13.265761"
  348 + fy="8.9303417"
  349 + fx="39.14772"
  350 + cy="8.9303417"
  351 + cx="39.14772"
  352 + gradientTransform="matrix(0.878817,0,0,1.025708,1.24328,2.850095)"
  353 + id="radialGradient640"
  354 + xlink:href="#linearGradient641"
  355 + inkscape:collect="always" />
  356 + <linearGradient
  357 + y2="48.805084"
  358 + x2="25.31245"
  359 + y1="25.335417"
  360 + x1="17.573946"
  361 + gradientTransform="scale(1.175636,0.850604)"
  362 + gradientUnits="userSpaceOnUse"
  363 + id="linearGradient374"
  364 + xlink:href="#linearGradient368"
  365 + inkscape:collect="always" />
  366 + <linearGradient
  367 + gradientUnits="userSpaceOnUse"
  368 + y2="23.600779"
  369 + x2="19.857769"
  370 + y1="38.962704"
  371 + x1="19.977491"
  372 + gradientTransform="scale(1.215669,0.822592)"
  373 + id="linearGradient384"
  374 + xlink:href="#linearGradient381"
  375 + inkscape:collect="always" />
  376 + </defs>
  377 + <sodipodi:namedview
  378 + showborder="true"
  379 + id="base"
  380 + pagecolor="#ffffff"
  381 + bordercolor="#666666"
  382 + borderopacity="1.0"
  383 + inkscape:pageopacity="0.0"
  384 + inkscape:pageshadow="2"
  385 + inkscape:zoom="13.618797"
  386 + inkscape:cx="24"
  387 + inkscape:cy="24.613205"
  388 + inkscape:current-layer="layer1"
  389 + showgrid="false"
  390 + inkscape:grid-bbox="true"
  391 + inkscape:document-units="px"
  392 + inkscape:window-width="1440"
  393 + inkscape:window-height="852"
  394 + inkscape:window-x="0"
  395 + inkscape:window-y="0"
  396 + inkscape:showpageshadow="false" />
  397 + <metadata
  398 + id="metadata4">
  399 + <rdf:RDF>
  400 + <cc:Work
  401 + rdf:about="">
  402 + <dc:format>image/svg+xml</dc:format>
  403 + <dc:type
  404 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  405 + <dc:title>Trash Full</dc:title>
  406 + <dc:date>2003-02-03</dc:date>
  407 + <dc:creator>
  408 + <cc:Agent>
  409 + <dc:title>Jakub Steiner</dc:title>
  410 + </cc:Agent>
  411 + </dc:creator>
  412 + <dc:subject>
  413 + <rdf:Bag>
  414 + <rdf:li>trash</rdf:li>
  415 + <rdf:li>delete</rdf:li>
  416 + <rdf:li>deleted files</rdf:li>
  417 + <rdf:li>waste</rdf:li>
  418 + <rdf:li>recycle</rdf:li>
  419 + <rdf:li>bin</rdf:li>
  420 + <rdf:li>full</rdf:li>
  421 + </rdf:Bag>
  422 + </dc:subject>
  423 + <dc:publisher>
  424 + <cc:Agent>
  425 + <dc:title>Novell, Inc.</dc:title>
  426 + </cc:Agent>
  427 + </dc:publisher>
  428 + <cc:license
  429 + rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
  430 + </cc:Work>
  431 + <cc:License
  432 + rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
  433 + <cc:permits
  434 + rdf:resource="http://web.resource.org/cc/Reproduction" />
  435 + <cc:permits
  436 + rdf:resource="http://web.resource.org/cc/Distribution" />
  437 + <cc:requires
  438 + rdf:resource="http://web.resource.org/cc/Notice" />
  439 + <cc:requires
  440 + rdf:resource="http://web.resource.org/cc/Attribution" />
  441 + <cc:permits
  442 + rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
  443 + <cc:requires
  444 + rdf:resource="http://web.resource.org/cc/ShareAlike" />
  445 + </cc:License>
  446 + </rdf:RDF>
  447 + </metadata>
  448 + <g
  449 + id="layer1"
  450 + inkscape:label="Layer 1"
  451 + inkscape:groupmode="layer"
  452 + transform="translate(-1.9364206,25.97742)">
  453 + <path
  454 + style="fill:#aeaeae;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
  455 + d="M 25.573309,-11.367274 L 39.023552,-10.341066 L 44.224653,-23.003395 L 38.070664,-18.678228 C 38.070664,-18.678228 35.431941,-24.83272 33.535358,-25.327483 C 31.638778,-25.822243 23.547033,-25.657322 23.547033,-25.657322 C 26.120772,-25.020805 28.121036,-20.5984 28.151784,-20.548234 C 28.954727,-19.238075 31.202357,-14.829528 31.202357,-14.829528 L 25.573309,-11.367274 z"
  456 + id="path41"
  457 + sodipodi:nodetypes="ccccccscc" />
  458 + <path
  459 + style="fill:#d5d5d5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
  460 + d="M 27.237312,-20.126383 L 22.785035,-11.632996 L 13.631964,-17.405201 C 13.631964,-17.405201 17.782526,-25.238907 21.053373,-25.238907 C 24.35189,-25.238907 25.82591,-22.395699 27.237312,-20.126383 z"
  461 + id="path130"
  462 + sodipodi:nodetypes="ccczc" />
  463 + <path
  464 + style="fill:#aeaeae;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
  465 + d="M 33.790949,0.039420776 L 25.119184,10.403397 L 33.39456,21.089879 L 33.547618,14.358991 C 33.547618,14.358991 39.643158,14.934236 41.042169,13.561435 C 42.441173,12.188634 48.261285,5.2669617 48.261285,5.2669617 C 46.392707,7.1478383 41.570981,6.5913532 41.512143,6.5919554 C 39.975593,6.6075524 33.894123,6.4656353 33.894123,6.4656353 L 33.790949,0.039420776 z"
  466 + id="path139"
  467 + sodipodi:nodetypes="ccccccscc" />
  468 + <path
  469 + style="fill:#d5d5d5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
  470 + d="M 41.929254,5.4089567 L 36.930779,-2.7749032 L 46.58596,-7.6610575 C 46.58596,-7.6610575 51.173548,-0.075011208 49.49281,2.7309777 C 47.797861,5.5607038 44.601303,5.3642417 41.929254,5.4089567 z"
  471 + id="path140"
  472 + sodipodi:nodetypes="ccczc" />
  473 + <path
  474 + style="fill:#aeaeae;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
  475 + d="M 18.626929,-0.56239567 L 14.346013,-11.836691 L 1.8629906,-10.954505 L 6.9874103,-7.2215585 C 6.9874103,-7.2215585 3.4484744,-2.2253151 3.9405135,-0.32802336 C 4.4325526,1.5692649 7.2084811,9.429705 7.2084811,9.429705 C 6.5102915,6.8720063 9.3976127,2.9704545 9.4264403,2.9191578 C 10.179327,1.5796085 13.335668,-3.6205749 13.335668,-3.6205749 L 18.626929,-0.56239567 z"
  476 + id="path142"
  477 + sodipodi:nodetypes="ccccccscc" />
  478 + <path
  479 + style="fill:#d5d5d5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
  480 + d="M 10.063585,3.991281 L 19.649913,3.740954 L 19.069021,14.546491 C 19.069021,14.546491 10.205778,14.738872 8.6120759,11.882554 C 7.0048953,9.0020693 8.7695652,6.3295242 10.063585,3.991281 z"
  481 + id="path143"
  482 + sodipodi:nodetypes="ccczc" />
  483 + </g>
  484 + <g
  485 + inkscape:label="trash"
  486 + id="layer2"
  487 + inkscape:groupmode="layer"
  488 + transform="translate(-1.9364206,25.97742)">
  489 + <g
  490 + transform="matrix(0.273209,0,0,0.273209,6.153125,9.65744)"
  491 + id="g620"
  492 + style="font-size:12px;fill:url(#linearGradient632);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2.13333321;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
  493 + i:knockout="Off" />
  494 + </g>
  495 +</svg>
BIN  artwork/tick.psd
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
73 setup.py
... ... @@ -0,0 +1,73 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 +Description missing
  4 +"""
  5 +
  6 +# we require setuptools because of dependencies and testing.
  7 +# we may provide a distutils fallback later.
  8 +from setuptools import setup
  9 +
  10 +extra = {}
  11 +try:
  12 + import babel
  13 +except ImportError:
  14 + pass
  15 +else:
  16 + extra['message_extractors'] = {
  17 + 'solace': [
  18 + ('**.py', 'python', None),
  19 + ('**/templates/**', 'jinja2', None),
  20 + ('**.js', 'javascript', None)
  21 + ]
  22 + }
  23 +
  24 +try:
  25 + from solace import scripts
  26 +except ImportError:
  27 + pass
  28 +else:
  29 + extra['cmdclass'] = {
  30 + 'runserver': scripts.RunserverCommand,
  31 + 'initdb': scripts.InitDatabaseCommand,
  32 + 'reset': scripts.ResetDatabase,
  33 + 'make_testdata': scripts.MakeTestData,
  34 + 'compile_catalog': scripts.CompileCatalogEx
  35 + }
  36 +
  37 +try:
  38 + import webdepcompress
  39 +except ImportError:
  40 + pass
  41 +else:
  42 + extra['webdepcompress_manager'] = 'solace.packs.pack_mgr'
  43 +
  44 +setup(
  45 + name='Solace',
  46 + version='0.1',
  47 + url='http://opensource.plurk.com/solace/',
  48 + license='BSD',
  49 + author='Plurk Inc.',
  50 + author_email='opensource@plurk.com',
  51 + description='Multilangual User Support Platform',
  52 + long_description=__doc__,
  53 + packages=['solace', 'solace.views', 'solace.i18n', 'solace.utils'],
  54 + package_data={
  55 + 'solace.i18n': ['*'],
  56 + 'solace': ['templates/*', 'static/*']
  57 + },
  58 + platforms='any',
  59 + test_suite='solace.tests.suite',
  60 + install_requires=[
  61 + 'Werkzeug>=0.5.1',
  62 + 'Jinja2',
  63 + 'Babel',
  64 + 'SQLAlchemy>=0.5',
  65 + 'creoleparser',
  66 + 'simplejson',
  67 + 'webdepcompress'
  68 + ],
  69 + tests_require=[
  70 + 'lxml',
  71 + 'html5lib'
  72 + ], **extra
  73 +)
14 solace/__init__.py
... ... @@ -0,0 +1,14 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 + solace
  4 + ~~~~~~
  5 +
  6 + Solace is a community driven support vehicle for Plurk that might also be
  7 + useful for others. It's heavily inspired by support forums such as PHPBB
  8 + and the stackoverflow system.
  9 +
  10 + :copyright: (c) 2009 by Plurk Inc., see AUTHORS for more details.
  11 + :license: BSD, see LICENSE for more details.
  12 +"""
  13 +# note on imports: This __init__ file must not import anything in order fo
  14 +# the solace.scripts module not importing anything. More information there.
413 solace/application.py
... ... @@ -0,0 +1,413 @@
  1 +# -*- coding: utf-8 -*-
  2 +"""
  3 + solace.application
  4 + ~~~~~~~~~~~~~~~~~~
  5 +
  6 + The WSGI application for Solace.
  7 +
  8 + :copyright: (c) 2009 by Plurk Inc., see AUTHORS for more details.
  9 + :license: BSD, see LICENSE for more details.
  10 +"""
  11 +import os
  12 +from urlparse import urlparse, urlsplit, urljoin
  13 +from fnmatch import fnmatch
  14 +from functools import update_wrapper
  15 +from simplejson import dumps
  16 +
  17 +from babel import UnknownLocaleError, Locale
  18 +from werkzeug import Request as RequestBase, Response, cached_property, \
  19 + import_string, redirect, SharedDataMiddleware, url_quote
  20 +from werkzeug.exceptions import HTTPException, NotFound, Forbidden
  21 +from werkzeug.routing import BuildError, RequestRedirect
  22 +from werkzeug.contrib.securecookie import SecureCookie
  23 +
  24 +from solace.utils.ctxlocal import local, local_mgr, LocalProperty
  25 +
  26 +
  27 +class Request(RequestBase):
  28 + """The request class."""
  29 +
  30 + in_api = False
  31 + _locale = None
  32 + _pulled_flash_messages = None
  33 +
  34 + def __init__(self, environ):
  35 + RequestBase.__init__(self, environ)
  36 + self.url_adapter = url_map.bind_to_environ(self.environ)
  37 + self.view_lang = self.match_exception = None
  38 + try:
  39 + self.endpoint, self.view_arguments = self.url_adapter.match()
  40 + view_lang = self.view_arguments.pop('lang_code', None)
  41 + if view_lang is not None:
  42 + try:
  43 + self.view_lang = Locale.parse(view_lang)
  44 + if not has_section(self.view_lang):
  45 + raise UnknownLocaleError(str(self.view_lang))
  46 + except UnknownLocaleError:
  47 + self.view_lang = None
  48 + self.match_exception = NotFound()
  49 + except HTTPException, e:
  50 + self.endpoint = self.view_arguments = None
  51 + self.match_exception = e
  52 + self.sql_queries = []
  53 + local.request = self
  54 +
  55 + current = LocalProperty('request')
  56 +
  57 + def dispatch(self):
  58 + """Where do we want to go today?"""
  59 + try:
  60 + if self.match_exception is not None:
  61 + raise self.match_exception
  62 + rv = self.view(self, **self.view_arguments)
  63 + except NotFound, e:
  64 + rv = get_view('core.not_found')(self)
  65 + if isinstance(rv, basestring):
  66 + rv = Response(rv, mimetype='text/html')
  67 + return rv
  68 +
  69 + def _get_locale(self):
  70 + """The locale of the incoming request. If a locale is unsupported, the
  71 + default english locale is used. If the locale is assigned it will be
  72 + stored in the session so that that language changes are persistent.
  73 + """
  74 + if self._locale is not None:
  75 + return self._locale
  76 + rv = self.session.get('locale')
  77 + if rv is not None:
  78 + rv = Locale.parse(rv)
  79 + # we could trust the cookie here because it's signed, but we do not
  80 + # because the configuration could have changed in the meantime.
  81 + if not has_section(rv):
  82 + rv = None
  83 + if rv is None:
  84 + rv = select_locale(self.accept_languages)
  85 + self._locale = rv
  86 + return rv
  87 + def _set_locale(self, locale):
  88 + self._locale = Locale.parse(locale)
  89 + self.__dict__.pop('translations', None)
  90 + self.session['locale'] = str(self._locale)
  91 + locale = property(_get_locale, _set_locale)
  92 + del _get_locale, _set_locale
  93 +
  94 + @cached_property
  95 + def translations(self):
  96 + """The translations for this request."""
  97 + return load_translations(self.locale)
  98 +
  99 + @property
  100 + def timezone_known(self):
  101 + """If the JavaScript on the client set the timezone already this returns
  102 + True, otherwise False.
  103 + """
  104 + return self.session.get('timezone') is not None
  105 +
  106 + @cached_property
  107 + def tzinfo(self):
  108 + """The timezone information."""
  109 + offset = self.session.get('timezone')
  110 + if offset is not None:
  111 + return Timezone(offset)
  112 +
  113 + @cached_property
  114 + def next_url(self):
  115 + """Sometimes we want to redirect to different URLs back or forth.
  116 + For example the login function uses this attribute to find out
  117 + where it should go.
  118 +
  119 + If there is a `next` parameter on the URL or in the form data, the
  120 + function will redirect there, if it's not there, it checks the
  121 + referrer.
  122 +
  123 + It's usually better to use the get_redirect_target method.
  124 + """
  125 + return self.get_redirect_target()
  126 +
  127 + def get_localized_next_url(self, locale=None):
  128 + """Like `next_url` but tries to go to the localized section."""
  129 + if locale is None:
  130 + locale = self.locale
  131 + next_url = self.get_redirect_target()
  132 + if next_url is None:
  133 + return
  134 + scheme, netloc, path, query = urlsplit(next_url)[:4]
  135 + path = path.decode('utf-8')
  136 +
  137 + # aha. we're redirecting somewhere out of our control
  138 + if netloc != self.host or not path.startswith(self.script_root):
  139 + return next_url
  140 +
  141 + path = path[len(self.script_root):]
  142 + try:
  143 + endpoint, values = self.url_adapter.match(path)
  144 + except NotFound, e:
  145