Skip to content
Browse files

Removed Pootle as a submodule and included in master.

  • Loading branch information...
1 parent ac5ca9d commit c96dd28ec98c0a8b739642a43fa02a629e864ff4 @capooti capooti committed May 31, 2012
Showing with 19,349 additions and 4 deletions.
  1. +0 −3 .gitmodules
  2. +0 −1 pootle
  3. +4 −0 pootle/.gitignore
  4. +340 −0 pootle/COPYING
  5. +41 −0 pootle/CREDITS
  6. +7,769 −0 pootle/ChangeLog
  7. +61 −0 pootle/INSTALL
  8. +15 −0 pootle/MANIFEST.in
  9. +25 −0 pootle/PKG-INFO
  10. +33 −0 pootle/PootleServer
  11. +120 −0 pootle/README
  12. +5 −0 pootle/REQUIREMENTS.txt
  13. +20 −0 pootle/apache/django.wsgi
  14. +16 −0 pootle/apache/django.wsgi.tmpl
  15. +29 −0 pootle/apache/pootle.virtenv.conf.example
  16. +4 −0 pootle/dbs/README
  17. 0 pootle/external_apps/contact_form_i18n/__init__.py
  18. +261 −0 pootle/external_apps/contact_form_i18n/forms.py
  19. +28 −0 pootle/external_apps/contact_form_i18n/urls.py
  20. +92 −0 pootle/external_apps/contact_form_i18n/views.py
  21. 0 pootle/external_apps/djblets/__init__.py
  22. 0 pootle/external_apps/djblets/siteconfig/__init__.py
  23. +35 −0 pootle/external_apps/djblets/siteconfig/admin.py
  24. +36 −0 pootle/external_apps/djblets/siteconfig/context_processors.py
  25. +170 −0 pootle/external_apps/djblets/siteconfig/django_settings.py
  26. +76 −0 pootle/external_apps/djblets/siteconfig/forms.py
  27. +71 −0 pootle/external_apps/djblets/siteconfig/managers.py
  28. +13 −0 pootle/external_apps/djblets/siteconfig/middleware.py
  29. +127 −0 pootle/external_apps/djblets/siteconfig/models.py
  30. +58 −0 pootle/external_apps/djblets/siteconfig/views.py
  31. +24 −0 pootle/external_apps/djblets/util/__init__.py
  32. +69 −0 pootle/external_apps/djblets/util/context_processors.py
  33. +57 −0 pootle/external_apps/djblets/util/dates.py
  34. +51 −0 pootle/external_apps/djblets/util/db.py
  35. +33 −0 pootle/external_apps/djblets/util/dbevolution.py
  36. +177 −0 pootle/external_apps/djblets/util/decorators.py
  37. +208 −0 pootle/external_apps/djblets/util/fields.py
  38. +80 −0 pootle/external_apps/djblets/util/http.py
  39. +269 −0 pootle/external_apps/djblets/util/misc.py
  40. +15 −0 pootle/external_apps/djblets/util/rooturl.py
  41. 0 pootle/external_apps/djblets/util/templatetags/__init__.py
  42. +57 −0 pootle/external_apps/djblets/util/templatetags/djblets_deco.py
  43. +71 −0 pootle/external_apps/djblets/util/templatetags/djblets_email.py
  44. +95 −0 pootle/external_apps/djblets/util/templatetags/djblets_forms.py
  45. +100 −0 pootle/external_apps/djblets/util/templatetags/djblets_images.py
  46. +59 −0 pootle/external_apps/djblets/util/templatetags/djblets_js.py
  47. +283 −0 pootle/external_apps/djblets/util/templatetags/djblets_utils.py
  48. +57 −0 pootle/external_apps/djblets/util/testing.py
  49. +243 −0 pootle/external_apps/djblets/util/tests.py
  50. 0 pootle/external_apps/profiles/__init__.py
  51. +43 −0 pootle/external_apps/profiles/urls.py
  52. +45 −0 pootle/external_apps/profiles/utils.py
  53. +337 −0 pootle/external_apps/profiles/views.py
  54. 0 pootle/external_apps/registration/__init__.py
  55. +11 −0 pootle/external_apps/registration/admin.py
  56. +134 −0 pootle/external_apps/registration/forms.py
  57. +262 −0 pootle/external_apps/registration/models.py
  58. +8 −0 pootle/external_apps/registration/signals.py
  59. +355 −0 pootle/external_apps/registration/tests.py
  60. +72 −0 pootle/external_apps/registration/urls.py
  61. +153 −0 pootle/external_apps/registration/views.py
  62. +135 −0 pootle/html/admin.css
  63. BIN pootle/html/favicon.ico
  64. BIN pootle/html/images/accept.png
  65. BIN pootle/html/images/apertium.png
  66. BIN pootle/html/images/arrow_refresh.png
  67. BIN pootle/html/images/arrow_up.png
  68. BIN pootle/html/images/asc.gif
  69. BIN pootle/html/images/ascdesc.gif
  70. BIN pootle/html/images/book_next.png
  71. BIN pootle/html/images/comment_add.png
  72. BIN pootle/html/images/context.png
  73. BIN pootle/html/images/copy.png
  74. BIN pootle/html/images/cross.png
  75. BIN pootle/html/images/cyan-bar.png
  76. BIN pootle/html/images/database_save.png
  77. BIN pootle/html/images/desc.gif
  78. BIN pootle/html/images/door_in.png
  79. BIN pootle/html/images/drive_network.png
  80. BIN pootle/html/images/edit.png
  81. BIN pootle/html/images/email_go.png
  82. BIN pootle/html/images/error.png
  83. BIN pootle/html/images/feed.png
  84. BIN pootle/html/images/folder.png
  85. BIN pootle/html/images/footer-border.png
  86. BIN pootle/html/images/gap.png
  87. BIN pootle/html/images/good.png
  88. BIN pootle/html/images/google-translate.png
  89. BIN pootle/html/images/green-bar.png
  90. BIN pootle/html/images/header-background-bottom.png
  91. BIN pootle/html/images/header-background.png
  92. BIN pootle/html/images/help.png
  93. BIN pootle/html/images/information.png
  94. BIN pootle/html/images/key_go.png
  95. BIN pootle/html/images/logo.png
  96. BIN pootle/html/images/newspaper_go.png
  97. BIN pootle/html/images/next.png
  98. BIN pootle/html/images/next2.png
  99. BIN pootle/html/images/none.png
  100. BIN pootle/html/images/page-bg.jpg
  101. BIN pootle/html/images/page.png
  102. BIN pootle/html/images/page_get.png
  103. BIN pootle/html/images/page_refresh.png
  104. BIN pootle/html/images/prev.png
  105. BIN pootle/html/images/prev2.png
  106. BIN pootle/html/images/purple-bar.png
  107. BIN pootle/html/images/red-bar.png
  108. BIN pootle/html/images/sarrow_down.png
  109. BIN pootle/html/images/sarrow_down_rtl.png
  110. BIN pootle/html/images/sarrow_up.png
  111. BIN pootle/html/images/sarrow_up_rtl.png
  112. BIN pootle/html/images/script_code.png
  113. BIN pootle/html/images/search-arrow.png
  114. BIN pootle/html/images/squiggle.png
  115. BIN pootle/html/images/suggest.png
  116. BIN pootle/html/images/throbber.gif
  117. BIN pootle/html/images/tick.png
  118. BIN pootle/html/images/user_comment.png
  119. BIN pootle/html/images/user_go.png
  120. BIN pootle/html/images/warning.png
  121. +98 −0 pootle/html/js/README
  122. +66 −0 pootle/html/js/admin.js
  123. +39 −0 pootle/html/js/correctpng.js
  124. +24 −0 pootle/html/js/jquery/jquery.bidi.js
  125. +69 −0 pootle/html/js/jquery/jquery.caret.js
  126. +96 −0 pootle/html/js/jquery/jquery.cookie.js
  127. +83 −0 pootle/html/js/jquery/jquery.fieldselection.js
  128. +154 −0 pootle/html/js/jquery/jquery.min.js
  129. +11 −0 pootle/html/js/jquery/jquery.scrollTo.min.js
  130. +95 −0 pootle/html/js/jquery/jquery.textarea-expander.js
  131. +28 −0 pootle/html/js/json2.min.js
  132. +73 −0 pootle/html/js/mt/apertium.js
  133. +78 −0 pootle/html/js/mt/google-translate.js
  134. +44 −0 pootle/html/js/search.js
  135. +523 −0 pootle/html/js/sorttable.js
  136. +326 −0 pootle/html/js/translatepage.js
  137. +1,683 −0 pootle/html/style.css
  138. +686 −0 pootle/html/translate.css
  139. +31 −0 pootle/import_pootle_prefs
  140. +20 −0 pootle/local_apps/pootle_app/__init__.py
  141. +97 −0 pootle/local_apps/pootle_app/admin.py
  142. +30 −0 pootle/local_apps/pootle_app/convert.py
  143. +42 −0 pootle/local_apps/pootle_app/forms.py
  144. 0 pootle/local_apps/pootle_app/lib/__init__.py
  145. +65 −0 pootle/local_apps/pootle_app/lib/util.py
  146. +83 −0 pootle/local_apps/pootle_app/lib/view_handler.py
  147. +192 −0 pootle/local_apps/pootle_app/management/__init__.py
  148. +140 −0 pootle/local_apps/pootle_app/management/commands/__init__.py
  149. +205 −0 pootle/local_apps/pootle_app/management/commands/initdb.py
  150. +235 −0 pootle/local_apps/pootle_app/management/commands/makepropermessages.py
  151. +42 −0 pootle/local_apps/pootle_app/management/commands/refresh_stats.py
  152. +40 −0 pootle/local_apps/pootle_app/management/commands/sync_stores.py
  153. +30 −0 pootle/local_apps/pootle_app/management/commands/update_from_templates.py
  154. +42 −0 pootle/local_apps/pootle_app/management/commands/update_stores.py
  155. +77 −0 pootle/local_apps/pootle_app/management/commands/update_translation_projects.py
  156. +49 −0 pootle/local_apps/pootle_app/management/commands/updatedb.py
  157. +26 −0 pootle/local_apps/pootle_app/models/__init__.py
  158. +195 −0 pootle/local_apps/pootle_app/models/directory.py
  159. +142 −0 pootle/local_apps/pootle_app/models/permissions.py
  160. +27 −0 pootle/local_apps/pootle_app/models/signals.py
  161. +44 −0 pootle/local_apps/pootle_app/models/suggestion.py
  162. +349 −0 pootle/local_apps/pootle_app/project_tree.py
  163. +18 −0 pootle/local_apps/pootle_app/templates/admin/admin_general.html
Sorry, we could not display the entire diff because too many files (669) changed.
View
3 .gitmodules
@@ -1,3 +0,0 @@
-[submodule "pootle"]
- path = pootle
- url = git@github.com:capooti/pootle.git
1 pootle
@@ -1 +0,0 @@
-Subproject commit 57aaafa89a35a051e0ed61bb3f19e7101d52be2d
View
4 pootle/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+dbs/pootle.db
+pootle_env
+
View
340 pootle/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
View
41 pootle/CREDITS
@@ -0,0 +1,41 @@
+Pootle Credits
+==============
+
+See the README file for an explanation of what Pootle is. See the ChangeLog (or
+svn history) for more detailed credits. These are people who have contributed
+documentation or code, but bug reports are also a valuable contribution! Many
+people have contributed suggestions etc on the translate-pootle list and these
+are also appreciated. Thank you for the many translators who translated the
+Pootle interface. If you've been left out, let us know!
+
+Alphabetical Order of Contributors
+----------------------------------
+
+Ahmed Toulan (أحمد طولون) (OpenCraft): development
+Alaa Abd El Fataah (علاء عبد الفتاح): development
+Abel Cheung (張國冠): feedback and patches for Chinese and CJK locales
+Andreas Pauley: development
+Behnam Esfahbod (بهنام اسفهبد): initial RTL testing and feedback
+Capel Brunker: development
+Charl van Niekerk: user interface improvements and testing
+Clytie Siddall: testing and feedback
+David Fraser: main initial development
+Daniel Schafer (Mozilla): development (Mozootle)
+Djihed Afifi (عفيفي جهاد): user interface improvements
+Dwayne Bailey: lots of different areas
+Friedel Wolff: development
+Gasper Zejn: user interface improvements
+Julen Ruiz Aizpuru: GSoC 2008, development
+Lars Kruse: improvements in several areas, testing, bug reports, patches
+Lucas Vieites: original Pootle SVG logo
+Matt Chisholm: bug fixes
+Miklos Vajna: patches and testing of version control
+Mohamed El-Sawy (محمد الصاوي) (OpenCraft): development
+Munzir Taha (منذر طه): initial RTL testing and feedback
+Nicolas François: Performance and customisability
+Sayamindu Dasgupta (সায়মিন্দু দাশগুপ্ত): Alternative source language
+Simos Xenitellis (Σίμος Ξενιτέλλης): user interface improvements
+Walter Leibbrandt: development
+Wil Clouser (Mozilla): debugging, testing, development (Mozootle)
+Wynand Winterbach: development
+Youssef Chahibi (يوسف الشهيبي): initial RTL testing and feedback
View
7,769 pootle/ChangeLog
7,769 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
61 pootle/INSTALL
@@ -0,0 +1,61 @@
+Requirements
+------------
+Pootle usually requires the latest Translate Toolkit package:
+http://translate.sourceforge.net/
+Note all the optional dependencies of the Translate Toolkit for optimal
+performance and functionality in Pootle.
+
+Python version 2.4 or later is required.
+
+Pootle requires Django (at least version 1.1)
+(http://www.djangoproject.com/)
+Django applications can run under Apache using mod_python or mod_wsgi,
+but they're also bundled with a standalone webserver that can be run
+from the command line. Pootle works well on all Django deployment
+scenarios. The standalone server is the easiest to set up and
+get running, whereas Apache will give the best performance.
+
+To run Pootle you need to have Django installed properly
+
+ tar xzvf Django-1.2.1-final.tar.gz
+ cd Django-1.2.1-final
+ sudo python setup.py install
+
+you can also install Django using easy_install
+
+ easy_install django
+
+The commandline utilities "zip" and "unzip" can speed up handling of ZIP files.
+For integration with a version control system, the relevant version control
+command line client must be installed and accessible from the PATH.
+
+Installation of an indexing engine (PyLucene or Xapian) is optional, but helps
+to speed up searching. Note that Xapian before version 1.0.13 is incompatible
+with Apache, and Pootle will not enable Xapian indexing if running under
+mod_python or mod_wsgi with problematic versions. Ensure that xapian-check is
+installed if you want to use Xapian to allow Pootle to check if it is safe to
+use it.
+
+Further information might be displayed on the admin page if Pootle detects
+anything non-optimal. More information on optimisation and optional software:
+ http://translate.sourceforge.net/wiki/pootle/optimisation
+
+
+Installation
+------------
+Pootle works perfectly directly from the source files without installation.
+
+Extract Pootle's source code, then change directory to inside the
+Pootle dir
+
+ tar xvf Pootle-......tar.gz
+ cd Pootle-.......
+
+If you want to install Pootle into your system, run
+
+ python setup.py install
+
+For installation under apache, see this page:
+ http://translate.sourceforge.net/wiki/pootle/apache
+and check the notes below about manually preparing your database.
+
View
15 pootle/MANIFEST.in
@@ -0,0 +1,15 @@
+graft html
+graft local_apps/pootle_app/templates
+graft local_apps/pootle_language/templates
+graft local_apps/pootle_notifications/templates
+graft local_apps/pootle_project/templates
+graft local_apps/pootle_store/templates
+graft local_apps/pootle_terminology/templates
+graft local_apps/pootle_translationproject/templates
+graft po
+graft mo
+graft templates
+include dbs/README
+include COPYING CREDITS ChangeLog INSTALL
+include *.py
+include MANIFEST.in
View
25 pootle/PKG-INFO
@@ -0,0 +1,25 @@
+Metadata-Version: 1.0
+Name: Pootle
+Version: 2.1.6
+Summary: An online collaborative localization tool.
+Home-page: http://translate.sourceforge.net/wiki/pootle/index
+Author: Translate.org.za
+Author-email: translate-devel@lists.sourceforge.net
+License: GNU General Public License (GPL)
+Download-URL: http://sourceforge.net/projects/translate/files/Pootle/
+Description: Pootle is used to create program translations.
+
+ It uses the Translate Toolkit to get access to translation files and therefore
+ can edit a variety of files (including PO and XLIFF files).
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Intended Audience :: Developers
+Classifier: Intended Audience :: End Users/Desktop
+Classifier: Intended Audience :: Information Technology
+Classifier: License :: OSI Approved :: GNU General Public License (GPL)
+Classifier: Programming Language :: Python
+Classifier: Topic :: Software Development :: Localization
+Classifier: Topic :: Text Processing :: LinguisticOperating System :: OS Independent
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: Unix
View
33 pootle/PootleServer
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 Zuza Software Foundation
+#
+# This file is part of translate.
+#
+# translate is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# translate 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with translate; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+"""This is just a simple script that runs the pootle main program"""
+
+# syspath_override is not needed and does not exist when Pootle is installed
+# from a distribution package or via "setup.py install"
+try:
+ import syspath_override
+except ImportError:
+ pass
+
+from pootle import PootleServer
+
+PootleServer.main()
+
View
120 pootle/README
@@ -0,0 +1,120 @@
+Pootle: a web translation and translation management engine
+===========================================================
+
+* How it works
+* Running
+* Manual preparation
+* Notes
+* Assignments
+* Common problems
+* Bug reporting/Feature requests
+* References
+
+
+How it works
+------------
+Pootle can host a number of translation projects for a number of languages. It
+allows a team to manage their files, permissions, projects, and also allows for
+translation on-line. Files can be downloaded for offline translation and later
+uploaded again.
+
+Pootle tries to lower the barrier of entry, but also provides tools to enable
+teams to work towards higher quality while welcoming newcomers.
+
+
+Running
+-------
+To run Pootle from sources, just run
+
+ ./PootleServer
+
+After installation with setup.py, PootleServer should also be accessible from
+the installation.
+
+If you are more familiar with Django projects, you can look into the manage.py
+commands as well.
+
+Use --help to see the other options. The defaults will generally work.
+
+Now visit http://localhost:8000/ to try out Pootle.
+
+To stop the server, press Ctrl-C.
+
+It is not recommended to run Pootle as the root user. For any non-trivial
+installation of Pootle, ensure that you use a database server (not SQLite) and
+use memcached. Other important information about optimisation is available in
+the Pootle documenation:
+ http://translate.sourceforge.net/wiki/pootle/optimisation
+
+Pootle can run under Apache using mod_python or mod_wsgi. Check this page for
+detailed instructions:
+ http://translate.sourceforge.net/wiki/pootle/apache
+
+
+Manual preparation
+------------------
+1. ./manage.py syncdb
+
+ At this step, you will be asked to create a superuser.
+ This user will be the administrator for your Pootle
+ installation.
+
+2. ./manage.py initdb
+
+ This step fills the database with initial data needed
+ to run Pootle.
+
+3. ./manage.py refresh_stats
+ Precalculate statisstics and indexes for existing translation projects.
+ This step is not strictly required, but without it Pootle will feel a bit
+ sluggish and slow when visiting accessing a page for the first time.
+
+4. ./manage.py runserver
+
+ You can now visit your Pootle installation at
+ http://localhost:8000. Note that the first time will
+ take a few moments to load, since Pootle needs to pre-compute
+ stats data for the translation files.
+
+
+Notes
+-----
+Files should be reindexed automatically. To ensure that all statistics and
+indices are up to date for the current projects and languages, run
+ PootleServer --refreshstats
+
+
+Assignments
+-----------
+Goals and assignments don't work at the moment, but should be re-instated soon.
+
+
+Common problems
+---------------
+If you get an error such as
+ sqlite3.OperationalError: unable to open database file
+then DATABASE_NAME in pootle/settings.py is pointing at an invalid directory.
+The default directory name is 'dbs' - ensure that this exists, and is writable
+for the user running Pootle.
+
+
+Bug Reporting/Feature requests
+------------------------------
+You can always report bugs or feature requests on the mailing list but because
+of the increase in users and the fact that bug reports do go missing it is
+probably best to place your bug report in Bugzilla: http://bugs.locamotion.org/
+
+If you have a traceback or a patch then please include it. Also please be quite
+specific about how the bug occured and what you expected to happen.
+
+If this is a feature request then try to be specific about how you think this
+feature should work.
+
+
+References
+----------
+Web: http://translate.sourceforge.net/wiki/pootle/index
+Bugzilla: http://bugs.locamotion.org/
+Mailing List: https://lists.sourceforge.net/lists/listinfo/translate-pootle
+IRC: #pootle on irc.freenode.org
+
View
5 pootle/REQUIREMENTS.txt
@@ -0,0 +1,5 @@
+Django==1.3.1
+Translate-Toolkit==1.9.0
+distribute==0.6.19
+lxml==2.3.4
+wsgiref==0.1.2
View
20 pootle/apache/django.wsgi
@@ -0,0 +1,20 @@
+import os
+import sys
+
+ROOT_DIR = '/home/capooti/git/github/qgis/qgis-django'
+APP_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle'
+LOCAL_APPS_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle/local_apps'
+EXT_APPS_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle/external_apps'
+sys.path.insert(0, ROOT_DIR)
+sys.path.insert(0, APP_DIR)
+sys.path.insert(0, LOCAL_APPS_DIR)
+sys.path.insert(0, EXT_APPS_DIR)
+
+import site
+VE_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle/pootle_env/lib/python2.5/site-packages'
+site.addsitedir(VE_DIR)
+
+import django.core.handlers.wsgi
+os.environ['DJANGO_SETTINGS_MODULE'] = 'pootle.settings'
+application = django.core.handlers.wsgi.WSGIHandler()
+
View
16 pootle/apache/django.wsgi.tmpl
@@ -0,0 +1,16 @@
+import os
+import sys
+
+ROOT_DIR = '/home/capooti/git/github/qgis/qgis-django'
+APP_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle'
+sys.path.insert(0, ROOT_DIR)
+sys.path.insert(0, APP_DIR)
+
+import site
+VE_DIR = '/home/capooti/git/github/qgis/qgis-django/pootle/pootle_env/lib/python2.6/site-packages'
+site.addsitedir(VE_DIR)
+
+import django.core.handlers.wsgi
+os.environ['DJANGO_SETTINGS_MODULE'] = 'pootle.settings'
+application = django.core.handlers.wsgi.WSGIHandler()
+
View
29 pootle/apache/pootle.virtenv.conf.example
@@ -0,0 +1,29 @@
+<VirtualHost *:80>
+ ServerAdmin pcorti@gmail.com
+ ServerName local.translate.com
+ ServerAlias www.local.translate.com.localhost
+
+ DocumentRoot /home/capooti/git/github/qgis/qgis-django/pootle
+
+ LogLevel info
+ CustomLog /var/log/apache2/translation.access.log combined
+ ErrorLog /var/log/apache2/translation.error.log
+
+ WSGIScriptAlias / /home/capooti/git/github/qgis/qgis-django/pootle/apache/django.wsgi
+ WSGIDaemonProcess pootle processes=2 threads=3 stack-size=1048576 maximum-requests=5000 inactivity-timeout=900 display-name=%{GROUP}
+ WSGIProcessGroup pootle
+
+ # directly serve static files like css and images, no need to go through mod_wsgi and django
+ Alias /pootle/html /home/capooti/git/github/qgis/qgis-django/pootle/html
+ <Directory /home/capooti/git/github/qgis/qgis-django/pootle/html>
+ Order deny,allow
+ Allow from all
+ </Directory>
+
+ # Allow downloading translation files directly
+ Alias /pootle/export /home/capooti/git/github/qgis/qgis-django/pootle/po
+ <Directory /home/capooti/git/github/qgis/qgis-django/pootle/po>
+ Order deny,allow
+ Allow from all
+ </Directory>
+</VirtualHost>
View
4 pootle/dbs/README
@@ -0,0 +1,4 @@
+This directory (dbs) contains two files:
+* pootle.db - The default SQLite database containing information about users,
+ languages, projects, etc. used by the Pootle server.
+* stats.db - Contains statistics about the PO files used by Pootle.
View
0 pootle/external_apps/contact_form_i18n/__init__.py
No changes.
View
261 pootle/external_apps/contact_form_i18n/forms.py
@@ -0,0 +1,261 @@
+"""
+A base contact form for allowing users to send email messages through
+a web interface, and a subclass demonstrating useful functionality.
+
+"""
+
+
+from django import forms
+from django.conf import settings
+from django.core.mail import send_mail
+from django.template import loader
+from django.template import RequestContext
+from django.contrib.sites.models import Site
+from django.utils.translation import ugettext_lazy as _
+
+
+# I put this on all required fields, because it's easier to pick up
+# on them with CSS or JavaScript if they have a class of "required"
+# in the HTML. Your mileage may vary.
+attrs_dict = { 'class': 'required' }
+
+
+class ContactForm(forms.Form):
+ """
+ Base contact form class from which all contact form classes should
+ inherit.
+
+ If you don't need any custom functionality, you can simply use
+ this form to provide basic contact functionality; it will collect
+ name, email address and message.
+
+ The ``contact_form`` view included in this application knows how
+ to work with this form and can handle many types of subclasses as
+ well (see below for a discussion of the important points), so in
+ many cases it will be all that you need. If you'd like to use this
+ form or a subclass of it from one of your own views, just do the
+ following:
+
+ 1. When you instantiate the form, pass the current ``HttpRequest``
+ object to the constructor as the keyword argument ``request``;
+ this is used internally by the base implementation, and also
+ made available so that subclasses can add functionality which
+ relies on inspecting the request.
+
+ 2. To send the message, call the form's ``save`` method, which
+ accepts the keyword argument ``fail_silently`` and defaults it
+ to ``False``. This argument is passed directly to
+ ``send_mail``, and allows you to suppress or raise exceptions
+ as needed for debugging. The ``save`` method has no return
+ value.
+
+ Other than that, treat it like any other form; validity checks and
+ validated data are handled normally, through the ``is_valid``
+ method and the ``cleaned_data`` dictionary.
+
+
+ Base implementation
+ -------------------
+
+ Under the hood, this form uses a somewhat abstracted interface in
+ order to make it easier to subclass and add functionality. There
+ are several important attributes subclasses may want to look at
+ overriding, all of which will work (in the base implementation) as
+ either plain attributes or as callable methods:
+
+ * ``from_email`` -- used to get the address to use in the
+ ``From:`` header of the message. The base implementation returns
+ the value of the ``DEFAULT_FROM_EMAIL`` setting.
+
+ * ``message`` -- used to get the message body as a string. The
+ base implementation renders a template using the form's
+ ``cleaned_data`` dictionary as context.
+
+ * ``recipient_list`` -- used to generate the list of recipients
+ for the message. The base implementation returns the email
+ addresses specified in the ``MANAGERS`` setting.
+
+ * ``subject`` -- used to generate the subject line for the
+ message. The base implementation returns the string 'Message
+ sent through the web site', with the name of the current
+ ``Site`` prepended.
+
+ * ``template_name`` -- used by the base ``message`` method to
+ determine which template to use for rendering the
+ message. Default is ``contact_form/contact_form.txt``.
+
+ Internally, the base implementation ``_get_message_dict`` method
+ collects ``from_email``, ``message``, ``recipient_list`` and
+ ``subject`` into a dictionary, which the ``save`` method then
+ passes directly to ``send_mail`` as keyword arguments.
+
+ Particularly important is the ``message`` attribute, with its base
+ implementation as a method which renders a template; because it
+ passes ``cleaned_data`` as the template context, any additional
+ fields added by a subclass will automatically be available in the
+ template. This means that many useful subclasses can get by with
+ just adding a few fields and possibly overriding
+ ``template_name``.
+
+ Much useful functionality can be achieved in subclasses without
+ having to override much of the above; adding additional validation
+ methods works the same as any other form, and typically only a few
+ items -- ``recipient_list`` and ``subject_line``, for example,
+ need to be overridden to achieve customized behavior.
+
+
+ Other notes for subclassing
+ ---------------------------
+
+ Subclasses which want to inspect the current ``HttpRequest`` to
+ add functionality can access it via the attribute ``request``; the
+ base ``message`` takes advantage of this to use ``RequestContext``
+ when rendering its template. See the ``AkismetContactForm``
+ subclass in this file for an example of using the request to
+ perform additional validation.
+
+ Subclasses which override ``__init__`` need to accept ``*args``
+ and ``**kwargs``, and pass them via ``super`` in order to ensure
+ proper behavior.
+
+ Subclasses should be careful if overriding ``_get_message_dict``,
+ since that method **must** return a dictionary suitable for
+ passing directly to ``send_mail`` (unless ``save`` is overridden
+ as well).
+
+ Overriding ``save`` is relatively safe, though remember that code
+ which uses your form will expect ``save`` to accept the
+ ``fail_silently`` keyword argument. In the base implementation,
+ that argument defaults to ``False``, on the assumption that it's
+ far better to notice errors than to silently not send mail from
+ the contact form (see also the Zen of Python: "Errors should never
+ pass silently, unless explicitly silenced").
+
+ """
+ def __init__(self, data=None, files=None, request=None, *args, **kwargs):
+ if request is None:
+ raise TypeError("Keyword argument 'request' must be supplied")
+ super(ContactForm, self).__init__(data=data, files=files, *args, **kwargs)
+ self.request = request
+
+ name = forms.CharField(max_length=100,
+ widget=forms.TextInput(attrs=attrs_dict),
+ label=_('Your name'))
+ email = forms.EmailField(widget=forms.TextInput(attrs=dict(attrs_dict,
+ maxlength=200)),
+ label=_('Your email address'))
+ body = forms.CharField(widget=forms.Textarea(attrs=attrs_dict),
+ label=_('Your message'))
+
+ recipient_list = [mail_tuple[1] for mail_tuple in settings.MANAGERS]
+
+ subject_template_name = "contact_form/contact_form_subject.txt"
+
+ template_name = 'contact_form/contact_form.txt'
+
+ def from_email(self):
+ return self.cleaned_data['email'] or settings.DEFAULT_FROM_EMAIL
+
+ def message(self):
+ """
+ Render the body of the message to a string.
+
+ """
+ if callable(self.template_name):
+ template_name = self.template_name()
+ else:
+ template_name = self.template_name
+ return loader.render_to_string(template_name,
+ self.get_context())
+
+ def subject(self):
+ """
+ Render the subject of the message to a string.
+
+ """
+ subject = loader.render_to_string(self.subject_template_name,
+ self.get_context())
+ return ''.join(subject.splitlines())
+
+ def get_context(self):
+ """
+ Return the context used to render the templates for the email
+ subject and body.
+
+ By default, this context includes:
+
+ * All of the validated values in the form, as variables of the
+ same names as their fields.
+
+ * The current ``Site`` object, as the variable ``site``.
+
+ * Any additional variables added by context processors (this
+ will be a ``RequestContext``).
+
+ """
+ if not self.is_valid():
+ raise ValueError("Cannot generate Context from invalid contact form")
+ return RequestContext(self.request,
+ dict(self.cleaned_data,
+ site=Site.objects.get_current()))
+
+ def get_message_dict(self):
+ """
+ Generate the various parts of the message and return them in a
+ dictionary, suitable for passing directly as keyword arguments
+ to ``django.core.mail.send_mail()``.
+
+ By default, the following values are returned:
+
+ * ``from_email``
+
+ * ``message``
+
+ * ``recipient_list``
+
+ * ``subject``
+
+ """
+ if not self.is_valid():
+ raise ValueError("Message cannot be sent from invalid contact form")
+ message_dict = {}
+ for message_part in ('from_email', 'message', 'recipient_list', 'subject'):
+ attr = getattr(self, message_part)
+ message_dict[message_part] = callable(attr) and attr() or attr
+ return message_dict
+
+ def save(self, fail_silently=False):
+ """
+ Build and send the email message.
+
+ """
+ send_mail(fail_silently=fail_silently, **self.get_message_dict())
+
+
+class AkismetContactForm(ContactForm):
+ """
+ Contact form which doesn't add any extra fields, but does add an
+ Akismet spam check to the validation routine.
+
+ Requires the setting ``AKISMET_API_KEY``, which should be a valid
+ Akismet API key.
+
+ """
+ def clean_body(self):
+ """
+ Perform Akismet validation of the message.
+
+ """
+ if 'body' in self.cleaned_data and getattr(settings, 'AKISMET_API_KEY', ''):
+ from akismet import Akismet
+ from django.utils.encoding import smart_str
+ akismet_api = Akismet(key=settings.AKISMET_API_KEY,
+ blog_url='http://%s/' % Site.objects.get_current().domain)
+ if akismet_api.verify_key():
+ akismet_data = { 'comment_type': 'comment',
+ 'referer': self.request.META.get('HTTP_REFERER', ''),
+ 'user_ip': self.request.META.get('REMOTE_ADDR', ''),
+ 'user_agent': self.request.META.get('HTTP_USER_AGENT', '') }
+ if akismet_api.comment_check(smart_str(self.cleaned_data['body']), data=akismet_data, build_data=True):
+ raise forms.ValidationError(_("Akismet thinks this message is spam"))
+ return self.cleaned_data['body']
View
28 pootle/external_apps/contact_form_i18n/urls.py
@@ -0,0 +1,28 @@
+"""
+Example URLConf for a contact form.
+
+Because the ``contact_form`` view takes configurable arguments, it's
+recommended that you manually place it somewhere in your URL
+configuration with the arguments you want. If you just prefer the
+default, however, you can hang this URLConf somewhere in your URL
+hierarchy (for best results with the defaults, include it under
+``/contact/``).
+
+"""
+
+
+from django.conf.urls.defaults import *
+from django.views.generic.simple import direct_to_template
+
+from contact_form_i18n.views import contact_form
+
+
+urlpatterns = patterns('',
+ url(r'^/?$',
+ contact_form,
+ name='contact_form'),
+ url(r'^sent/?$',
+ direct_to_template,
+ { 'template': 'contact_form/contact_form_sent.html' },
+ name='contact_form_sent'),
+ )
View
92 pootle/external_apps/contact_form_i18n/views.py
@@ -0,0 +1,92 @@
+"""
+View which can render and send email from a contact form.
+
+"""
+
+from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template import RequestContext
+
+from contact_form_i18n.forms import ContactForm
+
+
+def contact_form(request, form_class=ContactForm,
+ template_name='contact_form/contact_form.html',
+ success_url=None, extra_context=None,
+ fail_silently=False):
+ """
+ Render a contact form, validate its input and send an email
+ from it.
+
+ **Optional arguments:**
+
+ ``extra_context``
+ A dictionary of variables to add to the template context. Any
+ callable object in this dictionary will be called to produce
+ the end result which appears in the context.
+
+ ``fail_silently``
+ If ``True``, errors when sending the email will be silently
+ supressed (i.e., with no logging or reporting of any such
+ errors. Default value is ``False``.
+
+ ``form_class``
+ The form to use. If not supplied, this will default to
+ ``contact_form.forms.ContactForm``. If supplied, the form
+ class must implement a method named ``save()`` which sends the
+ email from the form; the form class must accept an
+ ``HttpRequest`` as the keyword argument ``request`` to its
+ constructor, and it must implement a method named ``save()``
+ which sends the email and which accepts the keyword argument
+ ``fail_silently``.
+
+ ``success_url``
+ The URL to redirect to after a successful submission. If not
+ supplied, this will default to the URL pointed to by the named
+ URL pattern ``contact_form_sent``.
+
+ ``template_name``
+ The template to use for rendering the contact form. If not
+ supplied, defaults to
+ :template:`contact_form/contact_form.html`.
+
+ **Context:**
+
+ ``form``
+ The form instance.
+
+ **Template:**
+
+ The value of the ``template_name`` keyword argument, or
+ :template:`contact_form/contact_form.html`.
+
+ """
+ #
+ # We set up success_url here, rather than as the default value for
+ # the argument. Trying to do it as the argument's default would
+ # mean evaluating the call to reverse() at the time this module is
+ # first imported, which introduces a circular dependency: to
+ # perform the reverse lookup we need access to contact_form/urls.py,
+ # but contact_form/urls.py in turn imports from this module.
+ #
+
+ if success_url is None:
+ success_url = reverse('contact_form_sent')
+ if request.method == 'POST':
+ form = form_class(data=request.POST, files=request.FILES, request=request)
+ if form.is_valid():
+ form.save(fail_silently=fail_silently)
+ return HttpResponseRedirect(success_url)
+ else:
+ form = form_class(request=request)
+
+ if extra_context is None:
+ extra_context = {}
+ context = RequestContext(request)
+ for key, value in extra_context.items():
+ context[key] = callable(value) and value() or value
+
+ return render_to_response(template_name,
+ { 'form': form },
+ context_instance=context)
View
0 pootle/external_apps/djblets/__init__.py
No changes.
View
0 pootle/external_apps/djblets/siteconfig/__init__.py
No changes.
View
35 pootle/external_apps/djblets/siteconfig/admin.py
@@ -0,0 +1,35 @@
+#
+# djblets/siteconfig/admin.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from django.contrib import admin
+
+from djblets.siteconfig.models import SiteConfiguration
+
+
+class SiteConfigurationAdmin(admin.ModelAdmin):
+ list_display = ('site', 'version')
+
+
+admin.site.register(SiteConfiguration, SiteConfigurationAdmin)
View
36 pootle/external_apps/djblets/siteconfig/context_processors.py
@@ -0,0 +1,36 @@
+#
+# djblets/siteconfig/context_processors.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from djblets.siteconfig.models import SiteConfiguration
+
+
+def siteconfig(request):
+ """
+ Exposes the site configuration as a siteconfig variable in templates.
+ """
+ try:
+ return {'siteconfig': SiteConfiguration.objects.get_current()}
+ except:
+ return {'siteconfig': None}
View
170 pootle/external_apps/djblets/siteconfig/django_settings.py
@@ -0,0 +1,170 @@
+#
+# djblets/siteconfig/django_settings.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+import os
+import time
+
+from django.conf import settings
+
+
+locale_settings_map = {
+ 'locale_timezone': { 'key': 'TIME_ZONE',
+ 'deserialize_func': str },
+ 'locale_language_code': 'LANGUAGE_CODE',
+ 'locale_date_format': 'DATE_FORMAT',
+ 'locale_datetime_format': 'DATETIME_FORMAT',
+ 'locale_default_charset': { 'key': 'DEFAULT_CHARSET',
+ 'deserialize_func': str },
+ 'locale_language_code': 'LANGUAGE_CODE',
+ 'locale_month_day_format': 'MONTH_DAY_FORMAT',
+ 'locale_time_format': 'TIME_FORMAT',
+ 'locale_year_month_format': 'YEAR_MONTH_FORMAT',
+}
+
+mail_settings_map = {
+ 'mail_server_address': 'SERVER_EMAIL',
+ 'mail_default_from': 'DEFAULT_FROM_EMAIL',
+ 'mail_host': 'EMAIL_HOST',
+ 'mail_port': 'EMAIL_PORT',
+ 'mail_host_user': 'EMAIL_HOST_USER',
+ 'mail_host_password': 'EMAIL_HOST_PASSWORD',
+ 'mail_use_tls': 'EMAIL_USE_TLS',
+}
+
+site_settings_map = {
+ 'site_media_root': 'MEDIA_ROOT',
+ 'site_media_url': 'MEDIA_URL',
+ 'site_prepend_www': 'PREPEND_WWW',
+ 'site_upload_temp_dir': 'FILE_UPLOAD_TEMP_DIR',
+ 'site_upload_max_memory_size': 'FILE_UPLOAD_MAX_MEMORY_SIZE',
+}
+
+cache_settings_map = {
+ 'cache_backend': 'CACHE_BACKEND',
+ 'cache_expiration_time': 'CACHE_EXPIRATION_TIME',
+}
+
+
+# Don't build unless we need it.
+_django_settings_map = {}
+
+
+def get_django_settings_map():
+ """
+ Returns the settings map for all Django settings that users may need
+ to customize.
+ """
+ if not _django_settings_map:
+ _django_settings_map.update(locale_settings_map)
+ _django_settings_map.update(mail_settings_map)
+ _django_settings_map.update(site_settings_map)
+ _django_settings_map.update(cache_settings_map)
+
+ return _django_settings_map
+
+
+def generate_defaults(settings_map):
+ """
+ Utility function to generate a defaults mapping.
+ """
+ defaults = {}
+
+ for siteconfig_key, setting_data in settings_map.iteritems():
+ if isinstance(setting_data, dict):
+ setting_key = setting_data['key']
+ else:
+ setting_key = setting_data
+
+ if hasattr(settings, setting_key):
+ defaults[siteconfig_key] = getattr(settings, setting_key)
+
+ return defaults
+
+
+def get_locale_defaults():
+ """
+ Returns the locale-related Django defaults that projects may want to
+ let users customize.
+ """
+ return generate_defaults(locale_settings_map)
+
+
+def get_mail_defaults():
+ """
+ Returns the mail-related Django defaults that projects may want to
+ let users customize.
+ """
+ return generate_defaults(mail_settings_map)
+
+
+def get_site_defaults():
+ """
+ Returns the site-related Django defaults that projects may want to
+ let users customize.
+ """
+ return generate_defaults(site_settings_map)
+
+
+def get_cache_defaults():
+ """
+ Returns the cache-related Django defaults that projects may want to
+ let users customize.
+ """
+ return generate_defaults(cache_settings_map)
+
+
+def get_django_defaults():
+ """
+ Returns all Django defaults that projects may want to let users customize.
+ """
+ return generate_defaults(get_django_settings_map())
+
+
+def apply_django_settings(siteconfig, settings_map=None):
+ """
+ Applies all settings from the site configuration to the Django settings
+ object.
+ """
+ if settings_map is None:
+ settings_map = get_django_settings_map()
+
+ for key, setting_data in settings_map.iteritems():
+ if key in siteconfig.settings:
+ value = siteconfig.get(key)
+
+ if isinstance(setting_data, dict):
+ setting_key = setting_data['key']
+
+ if ('deserialize_func' in setting_data and
+ callable(setting_data['deserialize_func'])):
+ value = setting_data['deserialize_func'](value)
+ else:
+ setting_key = setting_data
+
+ setattr(settings, setting_key, value)
+
+ if hasattr(time, 'tzset'):
+ os.environ['TZ'] = settings.TIME_ZONE
+ time.tzset()
View
76 pootle/external_apps/djblets/siteconfig/forms.py
@@ -0,0 +1,76 @@
+#
+# djblets/siteconfig/forms.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from django import forms
+
+
+class SiteSettingsForm(forms.Form):
+ """
+ A base form for loading/saving settings for a SiteConfiguration. This is
+ meant to be subclassed for different settings pages. Any fields defined
+ by the form will be loaded/saved automatically.
+ """
+ def __init__(self, siteconfig, *args, **kwargs):
+ forms.Form.__init__(self, *args, **kwargs)
+ self.siteconfig = siteconfig
+ self.disabled_fields = {}
+ self.disabled_reasons = {}
+
+ self.load()
+
+ def load(self):
+ """
+ Loads settings from the ```SiteConfiguration''' into this form.
+ The default values in the form will be the values in the settings.
+
+ This also handles setting disabled fields based on the
+ ```disabled_fields''' and ```disabled_reasons''' variables set on
+ this form.
+ """
+ if hasattr(self, "Meta"):
+ save_blacklist = getattr(self.Meta, "save_blacklist", [])
+
+ for field in self.fields:
+ value = self.siteconfig.get(field)
+
+ if isinstance(value, bool) or value:
+ self.fields[field].initial = value
+
+ if field in self.disabled_fields:
+ self.fields[field].widget.attrs['disabled'] = 'disabled'
+
+ def save(self):
+ """
+ Saves settings from the form back into the ```SiteConfiguration'''.
+ """
+ if not self.errors:
+ if hasattr(self, "Meta"):
+ save_blacklist = getattr(self.Meta, "save_blacklist", [])
+
+ for key, value in self.cleaned_data.iteritems():
+ if key not in save_blacklist:
+ self.siteconfig.settings[key] = value
+
+ self.siteconfig.save()
View
71 pootle/external_apps/djblets/siteconfig/managers.py
@@ -0,0 +1,71 @@
+#
+# djblets/siteconfig/managers.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from django.contrib.sites.models import Site
+from django.db import models
+
+
+_SITECONFIG_CACHE = {}
+
+
+class SiteConfigurationManager(models.Manager):
+ """
+ A Manager that provides a get_current function for retrieving the
+ SiteConfiguration for this particular running site.
+ """
+ def get_current(self):
+ """
+ Returns the site configuration on the active site.
+ """
+ from djblets.siteconfig.models import SiteConfiguration
+ global _SITECONFIG_CACHE
+
+ # This will handle raising a ImproperlyConfigured if not set up
+ # properly.
+ site = Site.objects.get_current()
+
+ if site.id not in _SITECONFIG_CACHE:
+ _SITECONFIG_CACHE[site.id] = \
+ SiteConfiguration.objects.get(site=site)
+
+ return _SITECONFIG_CACHE[site.id]
+
+ def clear_cache(self):
+ global _SITECONFIG_CACHE
+ _SITECONFIG_CACHE = {}
+
+ def check_expired(self):
+ """
+ Checks each cached SiteConfiguration to find out if its settings
+ have expired. This should be called on each request to ensure that
+ the copy of the settings is up-to-date in case another web server
+ worker process modifies the settings in the database.
+ """
+ global _SITECONFIG_CACHE
+
+ for key, siteconfig in _SITECONFIG_CACHE.copy().iteritems():
+ if siteconfig.is_expired():
+ # This is stale. Get rid of it so we can load it next time.
+ del _SITECONFIG_CACHE[key]
View
13 pootle/external_apps/djblets/siteconfig/middleware.py
@@ -0,0 +1,13 @@
+from djblets.siteconfig.models import SiteConfiguration
+
+
+class SettingsMiddleware(object):
+ """
+ Middleware that performs necessary operations for siteconfig settings.
+
+ Right now, the primary responsibility is to check on each request if
+ the settings have expired, so that a web server worker process doesn't
+ end up with a stale view of the site settings.
+ """
+ def process_request(self, request):
+ SiteConfiguration.objects.check_expired()
View
127 pootle/external_apps/djblets/siteconfig/models.py
@@ -0,0 +1,127 @@
+#
+# djblets/siteconfig/models.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from datetime import datetime
+
+from django.contrib.sites.models import Site
+from django.core.cache import cache
+from django.db import models
+
+from djblets.siteconfig.managers import SiteConfigurationManager
+from djblets.util.fields import JSONField
+
+
+_DEFAULTS = {}
+
+
+class SiteConfiguration(models.Model):
+ """
+ Configuration data for a site. The version and all persistent settings
+ are stored here.
+
+ The usual way to retrieve a SiteConfiguration is to use
+ ```SiteConfiguration.objects.get_current()'''
+ """
+ site = models.ForeignKey(Site, related_name="config")
+ version = models.CharField(max_length=20)
+ settings = JSONField()
+
+ objects = SiteConfigurationManager()
+
+ def __init__(self, *args, **kwargs):
+ models.Model.__init__(self, *args, **kwargs)
+ self._last_sync_time = datetime.now()
+
+ def get(self, key, default=None):
+ """
+ Retrieves a setting. If the setting is not found, the default value
+ will be returned. This is represented by the default parameter, if
+ passed in, or a global default if set.
+ """
+ if default is None and self.id in _DEFAULTS:
+ default = _DEFAULTS[self.id].get(key, None)
+
+ return self.settings.get(key, default)
+
+ def set(self, key, value):
+ """
+ Sets a setting. The key should be a string, but the value can be
+ any native Python object.
+ """
+ self.settings[key] = value
+
+ def add_defaults(self, defaults_dict):
+ """
+ Adds a dictionary of defaults to this SiteConfiguration. These
+ defaults will be used when calling ```get''', if that setting wasn't
+ saved in the database.
+ """
+ if self.id not in _DEFAULTS:
+ _DEFAULTS[self.id] = {}
+
+ _DEFAULTS[self.id].update(defaults_dict)
+
+ def add_default(self, key, default_value):
+ """
+ Adds a single default setting.
+ """
+ self.add_defaults({key: default_value})
+
+ def get_defaults(self):
+ """
+ Returns all default settings registered with this SiteConfiguration.
+ """
+ if self.id not in _DEFAULTS:
+ _DEFAULTS[self.id] = {}
+
+ return _DEFAULTS[self.id]
+
+ def is_expired(self):
+ """
+ Returns whether or not this SiteConfiguration is expired and needs
+ to be reloaded.
+ """
+ last_updated = cache.get(self.__get_sync_cache_key())
+ return (isinstance(last_updated, datetime) and
+ last_updated > self._last_sync_time)
+
+ def save(self, **kwargs):
+ now = datetime.now()
+ self._last_sync_time = now
+ cache.set(self.__get_sync_cache_key(), now)
+
+ # The cached siteconfig might be stale now. We'll want a refresh.
+ # Also refresh the Site cache, since callers may get this from
+ # Site.config.
+ SiteConfiguration.objects.clear_cache()
+ Site.objects.clear_cache()
+
+ super(SiteConfiguration, self).save(**kwargs)
+
+ def __get_sync_cache_key(self):
+ return "%s:siteconfig:%s:last-updated" % (self.site.domain, self.id)
+
+ def __unicode__(self):
+ return "%s (version %s)" % (unicode(self.site), self.version)
View
58 pootle/external_apps/djblets/siteconfig/views.py
@@ -0,0 +1,58 @@
+#
+# djblets/siteconfig/views.py
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from django.contrib.admin.views.decorators import staff_member_required
+from django.http import HttpResponseRedirect
+from django.shortcuts import render_to_response
+from django.template.context import RequestContext
+
+from djblets.siteconfig.models import SiteConfiguration
+
+
+@staff_member_required
+def site_settings(request, form_class,
+ template_name="siteconfig/settings.html",
+ extra_context={}):
+ """
+ Provides a front-end for customizing Review Board settings.
+ """
+ siteconfig = SiteConfiguration.objects.get_current()
+
+ if request.method == "POST":
+ form = form_class(siteconfig, request.POST, request.FILES)
+
+ if form.is_valid():
+ form.save()
+ return HttpResponseRedirect(".?saved=1")
+ else:
+ form = form_class(siteconfig)
+
+ context = {
+ 'form': form,
+ 'saved': request.GET.get('saved', 0)
+ }
+ context.update(extra_context)
+
+ return render_to_response(template_name, RequestContext(request, context))
View
24 pootle/external_apps/djblets/util/__init__.py
@@ -0,0 +1,24 @@
+#
+# __init__.py - djblets.util top-level
+#
+# Copyright (c) 2007 David Trowbridge
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
View
69 pootle/external_apps/djblets/util/context_processors.py
@@ -0,0 +1,69 @@
+#
+# djblets/util/context_processors.py
+#
+# Copyright (c) 2007-2009 Christian Hammond
+# Copyright (c) 2007-2009 David Trowbridge
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+import os
+from datetime import datetime
+
+from django.conf import settings
+
+def settingsVars(request):
+ return {'settings': settings}
+
+
+def siteRoot(request):
+ """
+ Exposes a SITE_ROOT variable in templates. This assumes that the
+ project has been configured with a SITE_ROOT settings variable and
+ proper support for basing the installation in a subdirectory.
+ """
+ return {'SITE_ROOT': settings.SITE_ROOT}
+
+
+def mediaSerial(request):
+ """
+ Exposes a media serial number that can be appended to a media filename
+ in order to make a URL that can be cached forever without fear of change.
+ The next time the file is updated and the server is restarted, a new
+ path will be accessed and cached.
+
+ This returns the value of settings.MEDIA_SERIAL, which must either be
+ set manually or ideally should be set to the value of
+ djblets.util.misc.generate_media_serial().
+ """
+ return {'MEDIA_SERIAL': getattr(settings, "MEDIA_SERIAL", "")}
+
+
+def ajaxSerial(request):
+ """
+ Exposes a serial number that can be appended to filenames involving
+ dynamic loads of URLs in order to make a URL that can be cached forever
+ without fear of change.
+
+ This returns the value of settings.AJAX_SERIAL, which must either be
+ set manually or ideally should be set to the value of
+ djblets.util.misc.generate_ajax_serial().
+ """
+ return {'AJAX_SERIAL': getattr(settings, "AJAX_SERIAL", "")}
View
57 pootle/external_apps/djblets/util/dates.py
@@ -0,0 +1,57 @@
+#
+# dates.py -- Date-related utilities.
+#
+# Copyright (c) 2008 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from datetime import datetime
+import time
+
+from django.db.models import DateField
+
+
+def http_date(timestamp):
+ """
+ A wrapper around Django's http_date that accepts DateFields and
+ datetime objects directly.
+ """
+ from django.utils.http import http_date
+
+ if isinstance(timestamp, (DateField, datetime)):
+ return http_date(time.mktime(timestamp.timetuple()))
+ elif isinstance(timestamp, basestring):
+ return timestamp
+ else:
+ return http_date(timestamp)
+
+
+def get_latest_timestamp(timestamps):
+ """
+ Returns the latest timestamp in a list of timestamps.
+ """
+ latest = None
+
+ for timestamp in timestamps:
+ if latest is None or timestamp > latest:
+ latest = timestamp
+
+ return latest
View
51 pootle/external_apps/djblets/util/db.py
@@ -0,0 +1,51 @@
+#
+# db.py -- Database utilities.
+#
+# Copyright (c) 2007 David Trowbridge
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+
+from django.db import models, IntegrityError
+
+
+class ConcurrencyManager(models.Manager):
+ """
+ A class designed to work around database concurrency issues.
+ """
+ def get_or_create(self, **kwargs):
+ """
+ A wrapper around get_or_create that makes a final attempt to get
+ the object if the creation fails.
+
+ This helps with race conditions in the database where, between the
+ original get() and the create(), another process created the object,
+ causing us to fail. We'll then execute a get().
+
+ This is still prone to race conditions, but they're even more rare.
+ A delete() would have to happen before the unexpected create() but
+ before the get().
+ """
+ try:
+ return super(ConcurrencyManager, self).get_or_create(**kwargs)
+ except IntegrityError:
+ kwargs.pop('defaults', None)
+ return self.get(**kwargs)
View
33 pootle/external_apps/djblets/util/dbevolution.py
@@ -0,0 +1,33 @@
+from django_evolution.mutations import BaseMutation
+
+
+class FakeChangeFieldType(BaseMutation):
+ """
+ Changes the type of the field to a similar type.
+ This is intended only when the new type is really a version of the
+ old type, such as a subclass of that Field object. The two fields
+ should be compatible or there could be migration issues.
+ """
+ def __init__(self, model_name, field_name, new_type):
+ self.model_name = model_name
+ self.field_name = field_name
+ self.new_type = new_type
+
+ def __str__(self):
+ return "FakeChangeFieldType('%s', '%s', '%s')" % \
+ (self.model_name, self.field_name, self.new_type)
+
+ def simulate(self, app_label, proj_sig):
+ app_sig = proj_sig[app_label]
+ model_sig = app_sig[self.model_name]
+ field_dict = model_sig['fields']
+ field_sig = field_dict[self.field_name]
+
+ field_sig['field_type'] = self.new_type
+
+ def mutate(self, app_label, proj_sig):
+ # We can just call simulate, since it does the same thing.
+ # We're not actually generating SQL, but rather tricking
+ # Django Evolution.
+ self.simulate(app_label, proj_sig)
+ return ""
View
177 pootle/external_apps/djblets/util/decorators.py
@@ -0,0 +1,177 @@
+#
+# decorators.py -- Miscellaneous, useful decorators. This might end up moving
+# to something with a different name.
+#
+# Copyright (c) 2007 David Trowbridge
+# Copyright (c) 2007 Christian Hammond
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+from inspect import getargspec
+
+from django import template
+from django.template import TemplateSyntaxError, Variable
+
+
+# The decorator decorator. This is copyright unknown, verbatim from
+# http://wiki.python.org/moin/PythonDecoratorLibrary
+def simple_decorator(decorator):
+ """This decorator can be used to turn simple functions
+ into well-behaved decorators, so long as the decorators
+ are fairly simple. If a decorator expects a function and
+ returns a function (no descriptors), and if it doesn't
+ modify function attributes or docstring, then it is
+ eligible to use this. Simply apply @simple_decorator to
+ your decorator and it will automatically preserve the
+ docstring and function attributes of functions to which
+ it is applied."""
+ def new_decorator(f):
+ g = decorator(f)
+ g.__name__ = f.__name__
+ g.__doc__ = f.__doc__
+ g.__dict__.update(f.__dict__)
+ return g
+ # Now a few lines needed to make simple_decorator itself
+ # be a well-behaved decorator.
+ new_decorator.__name__ = decorator.__name__
+ new_decorator.__doc__ = decorator.__doc__
+ new_decorator.__dict__.update(decorator.__dict__)
+ return new_decorator
+
+
+def basictag(takes_context=False):
+ """
+ A decorator similar to Django's @register.simple_tag that optionally
+ takes a context parameter. This condenses many tag implementations down
+ to a few lines of code.
+
+ Example:
+ @register.tag
+ @basictag(takes_context=True)
+ def printuser(context):
+ return context['user']
+ """
+ class BasicTagNode(template.Node):
+ def __init__(self, take_context, tag_name, tag_func, args):
+ self.takes_context = takes_context
+ self.tag_name = tag_name
+ self.tag_func = tag_func
+ self.args = args
+
+ def render(self, context):
+ args = [Variable(var).resolve(context) for var in self.args]
+
+ if self.takes_context:
+ return self.tag_func(context, *args)
+ else:
+ return self.tag_func(*args)
+
+ def basictag_func(tag_func):
+ def _setup_tag(parser, token):
+ bits = token.split_contents()
+ tag_name = bits[0]
+ del(bits[0])
+
+ params, xx, xxx, defaults = getargspec(tag_func)
+ max_args = len(params)
+
+ if takes_context:
+ if params[0] == 'context':
+ max_args -= 1 # Ignore context
+ else:
+ raise TemplateSyntaxError, \
+ "Any tag function decorated with takes_context=True " \
+ "must have a first argument of 'context'"
+
+ min_args = max_args - len(defaults or [])
+
+ if not min_args <= len(bits) <= max_args:
+ if min_args == max_args:
+ raise TemplateSyntaxError, \
+ "%r tag takes %d arguments." % (tag_name, min_args)
+ else:
+ raise TemplateSyntaxError, \
+ "%r tag takes %d to %d arguments, got %d." % \
+ (tag_name, min_args, max_args, len(bits))
+