1.1 --- a/COPYING.txt Sun Jun 06 16:20:14 2010 +0200
1.2 +++ b/COPYING.txt Mon Jun 07 01:14:02 2010 +0200
1.3 @@ -1,6 +1,34 @@
1.4 -Roundup Licensing
1.5 +Licence Agreement
1.6 -----------------
1.7
1.8 +Copyright (C) 2010 Paul Boddie <paul@boddie.org.uk>
1.9 +Copyright (c) 2003-2009 Richard Jones <richard@mechanicalcat.net>
1.10 +Copyright (c) 2002 eKit.com Inc (http://www.ekit.com/)
1.11 +Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
1.12 +
1.13 +Licensing notice:
1.14 +
1.15 +This software is free software; you can redistribute it and/or
1.16 +modify it under the terms of the GNU General Public License as
1.17 +published by the Free Software Foundation; either version 2 of
1.18 +the License, or (at your option) any later version.
1.19 +
1.20 +This software is distributed in the hope that it will be useful,
1.21 +but WITHOUT ANY WARRANTY; without even the implied warranty of
1.22 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.23 +GNU General Public License for more details.
1.24 +
1.25 +You should have received a copy of the GNU General Public
1.26 +License along with this library; see the file LICENCE.txt
1.27 +If not, write to the Free Software Foundation, Inc.,
1.28 +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
1.29 +
1.30 +Roundup Licensing Notices
1.31 +-------------------------
1.32 +
1.33 +These notices have been preserved to fulfil the terms stated below. However,
1.34 +the content as a whole is licensed according to the terms given above.
1.35 +
1.36 Copyright (c) 2003-2009 Richard Jones (richard@mechanicalcat.net)
1.37 Copyright (c) 2002 eKit.com Inc (http://www.ekit.com/)
1.38 Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/LICENCE.txt Mon Jun 07 01:14:02 2010 +0200
2.3 @@ -0,0 +1,339 @@
2.4 + GNU GENERAL PUBLIC LICENSE
2.5 + Version 2, June 1991
2.6 +
2.7 + Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
2.8 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2.9 + Everyone is permitted to copy and distribute verbatim copies
2.10 + of this license document, but changing it is not allowed.
2.11 +
2.12 + Preamble
2.13 +
2.14 + The licenses for most software are designed to take away your
2.15 +freedom to share and change it. By contrast, the GNU General Public
2.16 +License is intended to guarantee your freedom to share and change free
2.17 +software--to make sure the software is free for all its users. This
2.18 +General Public License applies to most of the Free Software
2.19 +Foundation's software and to any other program whose authors commit to
2.20 +using it. (Some other Free Software Foundation software is covered by
2.21 +the GNU Lesser General Public License instead.) You can apply it to
2.22 +your programs, too.
2.23 +
2.24 + When we speak of free software, we are referring to freedom, not
2.25 +price. Our General Public Licenses are designed to make sure that you
2.26 +have the freedom to distribute copies of free software (and charge for
2.27 +this service if you wish), that you receive source code or can get it
2.28 +if you want it, that you can change the software or use pieces of it
2.29 +in new free programs; and that you know you can do these things.
2.30 +
2.31 + To protect your rights, we need to make restrictions that forbid
2.32 +anyone to deny you these rights or to ask you to surrender the rights.
2.33 +These restrictions translate to certain responsibilities for you if you
2.34 +distribute copies of the software, or if you modify it.
2.35 +
2.36 + For example, if you distribute copies of such a program, whether
2.37 +gratis or for a fee, you must give the recipients all the rights that
2.38 +you have. You must make sure that they, too, receive or can get the
2.39 +source code. And you must show them these terms so they know their
2.40 +rights.
2.41 +
2.42 + We protect your rights with two steps: (1) copyright the software, and
2.43 +(2) offer you this license which gives you legal permission to copy,
2.44 +distribute and/or modify the software.
2.45 +
2.46 + Also, for each author's protection and ours, we want to make certain
2.47 +that everyone understands that there is no warranty for this free
2.48 +software. If the software is modified by someone else and passed on, we
2.49 +want its recipients to know that what they have is not the original, so
2.50 +that any problems introduced by others will not reflect on the original
2.51 +authors' reputations.
2.52 +
2.53 + Finally, any free program is threatened constantly by software
2.54 +patents. We wish to avoid the danger that redistributors of a free
2.55 +program will individually obtain patent licenses, in effect making the
2.56 +program proprietary. To prevent this, we have made it clear that any
2.57 +patent must be licensed for everyone's free use or not licensed at all.
2.58 +
2.59 + The precise terms and conditions for copying, distribution and
2.60 +modification follow.
2.61 +
2.62 + GNU GENERAL PUBLIC LICENSE
2.63 + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
2.64 +
2.65 + 0. This License applies to any program or other work which contains
2.66 +a notice placed by the copyright holder saying it may be distributed
2.67 +under the terms of this General Public License. The "Program", below,
2.68 +refers to any such program or work, and a "work based on the Program"
2.69 +means either the Program or any derivative work under copyright law:
2.70 +that is to say, a work containing the Program or a portion of it,
2.71 +either verbatim or with modifications and/or translated into another
2.72 +language. (Hereinafter, translation is included without limitation in
2.73 +the term "modification".) Each licensee is addressed as "you".
2.74 +
2.75 +Activities other than copying, distribution and modification are not
2.76 +covered by this License; they are outside its scope. The act of
2.77 +running the Program is not restricted, and the output from the Program
2.78 +is covered only if its contents constitute a work based on the
2.79 +Program (independent of having been made by running the Program).
2.80 +Whether that is true depends on what the Program does.
2.81 +
2.82 + 1. You may copy and distribute verbatim copies of the Program's
2.83 +source code as you receive it, in any medium, provided that you
2.84 +conspicuously and appropriately publish on each copy an appropriate
2.85 +copyright notice and disclaimer of warranty; keep intact all the
2.86 +notices that refer to this License and to the absence of any warranty;
2.87 +and give any other recipients of the Program a copy of this License
2.88 +along with the Program.
2.89 +
2.90 +You may charge a fee for the physical act of transferring a copy, and
2.91 +you may at your option offer warranty protection in exchange for a fee.
2.92 +
2.93 + 2. You may modify your copy or copies of the Program or any portion
2.94 +of it, thus forming a work based on the Program, and copy and
2.95 +distribute such modifications or work under the terms of Section 1
2.96 +above, provided that you also meet all of these conditions:
2.97 +
2.98 + a) You must cause the modified files to carry prominent notices
2.99 + stating that you changed the files and the date of any change.
2.100 +
2.101 + b) You must cause any work that you distribute or publish, that in
2.102 + whole or in part contains or is derived from the Program or any
2.103 + part thereof, to be licensed as a whole at no charge to all third
2.104 + parties under the terms of this License.
2.105 +
2.106 + c) If the modified program normally reads commands interactively
2.107 + when run, you must cause it, when started running for such
2.108 + interactive use in the most ordinary way, to print or display an
2.109 + announcement including an appropriate copyright notice and a
2.110 + notice that there is no warranty (or else, saying that you provide
2.111 + a warranty) and that users may redistribute the program under
2.112 + these conditions, and telling the user how to view a copy of this
2.113 + License. (Exception: if the Program itself is interactive but
2.114 + does not normally print such an announcement, your work based on
2.115 + the Program is not required to print an announcement.)
2.116 +
2.117 +These requirements apply to the modified work as a whole. If
2.118 +identifiable sections of that work are not derived from the Program,
2.119 +and can be reasonably considered independent and separate works in
2.120 +themselves, then this License, and its terms, do not apply to those
2.121 +sections when you distribute them as separate works. But when you
2.122 +distribute the same sections as part of a whole which is a work based
2.123 +on the Program, the distribution of the whole must be on the terms of
2.124 +this License, whose permissions for other licensees extend to the
2.125 +entire whole, and thus to each and every part regardless of who wrote it.
2.126 +
2.127 +Thus, it is not the intent of this section to claim rights or contest
2.128 +your rights to work written entirely by you; rather, the intent is to
2.129 +exercise the right to control the distribution of derivative or
2.130 +collective works based on the Program.
2.131 +
2.132 +In addition, mere aggregation of another work not based on the Program
2.133 +with the Program (or with a work based on the Program) on a volume of
2.134 +a storage or distribution medium does not bring the other work under
2.135 +the scope of this License.
2.136 +
2.137 + 3. You may copy and distribute the Program (or a work based on it,
2.138 +under Section 2) in object code or executable form under the terms of
2.139 +Sections 1 and 2 above provided that you also do one of the following:
2.140 +
2.141 + a) Accompany it with the complete corresponding machine-readable
2.142 + source code, which must be distributed under the terms of Sections
2.143 + 1 and 2 above on a medium customarily used for software interchange; or,
2.144 +
2.145 + b) Accompany it with a written offer, valid for at least three
2.146 + years, to give any third party, for a charge no more than your
2.147 + cost of physically performing source distribution, a complete
2.148 + machine-readable copy of the corresponding source code, to be
2.149 + distributed under the terms of Sections 1 and 2 above on a medium
2.150 + customarily used for software interchange; or,
2.151 +
2.152 + c) Accompany it with the information you received as to the offer
2.153 + to distribute corresponding source code. (This alternative is
2.154 + allowed only for noncommercial distribution and only if you
2.155 + received the program in object code or executable form with such
2.156 + an offer, in accord with Subsection b above.)
2.157 +
2.158 +The source code for a work means the preferred form of the work for
2.159 +making modifications to it. For an executable work, complete source
2.160 +code means all the source code for all modules it contains, plus any
2.161 +associated interface definition files, plus the scripts used to
2.162 +control compilation and installation of the executable. However, as a
2.163 +special exception, the source code distributed need not include
2.164 +anything that is normally distributed (in either source or binary
2.165 +form) with the major components (compiler, kernel, and so on) of the
2.166 +operating system on which the executable runs, unless that component
2.167 +itself accompanies the executable.
2.168 +
2.169 +If distribution of executable or object code is made by offering
2.170 +access to copy from a designated place, then offering equivalent
2.171 +access to copy the source code from the same place counts as
2.172 +distribution of the source code, even though third parties are not
2.173 +compelled to copy the source along with the object code.
2.174 +
2.175 + 4. You may not copy, modify, sublicense, or distribute the Program
2.176 +except as expressly provided under this License. Any attempt
2.177 +otherwise to copy, modify, sublicense or distribute the Program is
2.178 +void, and will automatically terminate your rights under this License.
2.179 +However, parties who have received copies, or rights, from you under
2.180 +this License will not have their licenses terminated so long as such
2.181 +parties remain in full compliance.
2.182 +
2.183 + 5. You are not required to accept this License, since you have not
2.184 +signed it. However, nothing else grants you permission to modify or
2.185 +distribute the Program or its derivative works. These actions are
2.186 +prohibited by law if you do not accept this License. Therefore, by
2.187 +modifying or distributing the Program (or any work based on the
2.188 +Program), you indicate your acceptance of this License to do so, and
2.189 +all its terms and conditions for copying, distributing or modifying
2.190 +the Program or works based on it.
2.191 +
2.192 + 6. Each time you redistribute the Program (or any work based on the
2.193 +Program), the recipient automatically receives a license from the
2.194 +original licensor to copy, distribute or modify the Program subject to
2.195 +these terms and conditions. You may not impose any further
2.196 +restrictions on the recipients' exercise of the rights granted herein.
2.197 +You are not responsible for enforcing compliance by third parties to
2.198 +this License.
2.199 +
2.200 + 7. If, as a consequence of a court judgment or allegation of patent
2.201 +infringement or for any other reason (not limited to patent issues),
2.202 +conditions are imposed on you (whether by court order, agreement or
2.203 +otherwise) that contradict the conditions of this License, they do not
2.204 +excuse you from the conditions of this License. If you cannot
2.205 +distribute so as to satisfy simultaneously your obligations under this
2.206 +License and any other pertinent obligations, then as a consequence you
2.207 +may not distribute the Program at all. For example, if a patent
2.208 +license would not permit royalty-free redistribution of the Program by
2.209 +all those who receive copies directly or indirectly through you, then
2.210 +the only way you could satisfy both it and this License would be to
2.211 +refrain entirely from distribution of the Program.
2.212 +
2.213 +If any portion of this section is held invalid or unenforceable under
2.214 +any particular circumstance, the balance of the section is intended to
2.215 +apply and the section as a whole is intended to apply in other
2.216 +circumstances.
2.217 +
2.218 +It is not the purpose of this section to induce you to infringe any
2.219 +patents or other property right claims or to contest validity of any
2.220 +such claims; this section has the sole purpose of protecting the
2.221 +integrity of the free software distribution system, which is
2.222 +implemented by public license practices. Many people have made
2.223 +generous contributions to the wide range of software distributed
2.224 +through that system in reliance on consistent application of that
2.225 +system; it is up to the author/donor to decide if he or she is willing
2.226 +to distribute software through any other system and a licensee cannot
2.227 +impose that choice.
2.228 +
2.229 +This section is intended to make thoroughly clear what is believed to
2.230 +be a consequence of the rest of this License.
2.231 +
2.232 + 8. If the distribution and/or use of the Program is restricted in
2.233 +certain countries either by patents or by copyrighted interfaces, the
2.234 +original copyright holder who places the Program under this License
2.235 +may add an explicit geographical distribution limitation excluding
2.236 +those countries, so that distribution is permitted only in or among
2.237 +countries not thus excluded. In such case, this License incorporates
2.238 +the limitation as if written in the body of this License.
2.239 +
2.240 + 9. The Free Software Foundation may publish revised and/or new versions
2.241 +of the General Public License from time to time. Such new versions will
2.242 +be similar in spirit to the present version, but may differ in detail to
2.243 +address new problems or concerns.
2.244 +
2.245 +Each version is given a distinguishing version number. If the Program
2.246 +specifies a version number of this License which applies to it and "any
2.247 +later version", you have the option of following the terms and conditions
2.248 +either of that version or of any later version published by the Free
2.249 +Software Foundation. If the Program does not specify a version number of
2.250 +this License, you may choose any version ever published by the Free Software
2.251 +Foundation.
2.252 +
2.253 + 10. If you wish to incorporate parts of the Program into other free
2.254 +programs whose distribution conditions are different, write to the author
2.255 +to ask for permission. For software which is copyrighted by the Free
2.256 +Software Foundation, write to the Free Software Foundation; we sometimes
2.257 +make exceptions for this. Our decision will be guided by the two goals
2.258 +of preserving the free status of all derivatives of our free software and
2.259 +of promoting the sharing and reuse of software generally.
2.260 +
2.261 + NO WARRANTY
2.262 +
2.263 + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
2.264 +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
2.265 +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
2.266 +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
2.267 +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2.268 +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
2.269 +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
2.270 +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
2.271 +REPAIR OR CORRECTION.
2.272 +
2.273 + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
2.274 +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
2.275 +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
2.276 +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
2.277 +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
2.278 +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
2.279 +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
2.280 +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
2.281 +POSSIBILITY OF SUCH DAMAGES.
2.282 +
2.283 + END OF TERMS AND CONDITIONS
2.284 +
2.285 + How to Apply These Terms to Your New Programs
2.286 +
2.287 + If you develop a new program, and you want it to be of the greatest
2.288 +possible use to the public, the best way to achieve this is to make it
2.289 +free software which everyone can redistribute and change under these terms.
2.290 +
2.291 + To do so, attach the following notices to the program. It is safest
2.292 +to attach them to the start of each source file to most effectively
2.293 +convey the exclusion of warranty; and each file should have at least
2.294 +the "copyright" line and a pointer to where the full notice is found.
2.295 +
2.296 + <one line to give the program's name and a brief idea of what it does.>
2.297 + Copyright (C) <year> <name of author>
2.298 +
2.299 + This program is free software; you can redistribute it and/or modify
2.300 + it under the terms of the GNU General Public License as published by
2.301 + the Free Software Foundation; either version 2 of the License, or
2.302 + (at your option) any later version.
2.303 +
2.304 + This program is distributed in the hope that it will be useful,
2.305 + but WITHOUT ANY WARRANTY; without even the implied warranty of
2.306 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2.307 + GNU General Public License for more details.
2.308 +
2.309 + You should have received a copy of the GNU General Public License along
2.310 + with this program; if not, write to the Free Software Foundation, Inc.,
2.311 + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2.312 +
2.313 +Also add information on how to contact you by electronic and paper mail.
2.314 +
2.315 +If the program is interactive, make it output a short notice like this
2.316 +when it starts in an interactive mode:
2.317 +
2.318 + Gnomovision version 69, Copyright (C) year name of author
2.319 + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
2.320 + This is free software, and you are welcome to redistribute it
2.321 + under certain conditions; type `show c' for details.
2.322 +
2.323 +The hypothetical commands `show w' and `show c' should show the appropriate
2.324 +parts of the General Public License. Of course, the commands you use may
2.325 +be called something other than `show w' and `show c'; they could even be
2.326 +mouse-clicks or menu items--whatever suits your program.
2.327 +
2.328 +You should also get your employer (if you work as a programmer) or your
2.329 +school, if any, to sign a "copyright disclaimer" for the program, if
2.330 +necessary. Here is a sample; alter the names:
2.331 +
2.332 + Yoyodyne, Inc., hereby disclaims all copyright interest in the program
2.333 + `Gnomovision' (which makes passes at compilers) written by James Hacker.
2.334 +
2.335 + <signature of Ty Coon>, 1 April 1989
2.336 + Ty Coon, President of Vice
2.337 +
2.338 +This General Public License does not permit incorporating your program into
2.339 +proprietary programs. If your program is a subroutine library, you may
2.340 +consider it more useful to permit linking proprietary applications with the
2.341 +library. If this is what you want to do, use the GNU Lesser General
2.342 +Public License instead of this License.
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/themes/mercurialroundup/TEMPLATE-INFO.txt Mon Jun 07 01:14:02 2010 +0200
3.3 @@ -0,0 +1,7 @@
3.4 +Name: mercurialroundup
3.5 +Description: This is a generic issue tracker that may be used to track bugs,
3.6 + feature requests, project issues or any number of other types
3.7 + of issues. This template has been modified to resemble the
3.8 + Mercurial Web site's appearance.
3.9 +Intended-For: All first-time Roundup users
3.10 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/themes/mercurialroundup/detectors/messagesummary.py Mon Jun 07 01:14:02 2010 +0200
4.3 @@ -0,0 +1,19 @@
4.4 +#$Id: messagesummary.py,v 1.2 2007-04-03 06:47:21 a1s Exp $
4.5 +
4.6 +from roundup.mailgw import parseContent
4.7 +
4.8 +def summarygenerator(db, cl, nodeid, newvalues):
4.9 + ''' If the message doesn't have a summary, make one for it.
4.10 + '''
4.11 + if newvalues.has_key('summary') or not newvalues.has_key('content'):
4.12 + return
4.13 +
4.14 + summary, content = parseContent(newvalues['content'], config=db.config)
4.15 + newvalues['summary'] = summary
4.16 +
4.17 +
4.18 +def init(db):
4.19 + # fire before changes are made
4.20 + db.msg.audit('create', summarygenerator)
4.21 +
4.22 +# vim: set filetype=python ts=4 sw=4 et si
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/themes/mercurialroundup/detectors/nosyreaction.py Mon Jun 07 01:14:02 2010 +0200
5.3 @@ -0,0 +1,144 @@
5.4 +#
5.5 +# Copyright (c) 2001 Bizar Software Pty Ltd (http://www.bizarsoftware.com.au/)
5.6 +# This module is free software, and you may redistribute it and/or modify
5.7 +# under the same terms as Python, so long as this copyright message and
5.8 +# disclaimer are retained in their original form.
5.9 +#
5.10 +# IN NO EVENT SHALL BIZAR SOFTWARE PTY LTD BE LIABLE TO ANY PARTY FOR
5.11 +# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING
5.12 +# OUT OF THE USE OF THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE
5.13 +# POSSIBILITY OF SUCH DAMAGE.
5.14 +#
5.15 +# BIZAR SOFTWARE PTY LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
5.16 +# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
5.17 +# FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
5.18 +# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
5.19 +# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
5.20 +#
5.21 +#$Id: nosyreaction.py,v 1.4 2005-04-04 08:47:14 richard Exp $
5.22 +
5.23 +# Python 2.3 ... 2.6 compatibility:
5.24 +from roundup.anypy.sets_ import set
5.25 +
5.26 +from roundup import roundupdb, hyperdb
5.27 +
5.28 +def nosyreaction(db, cl, nodeid, oldvalues):
5.29 + ''' A standard detector is provided that watches for additions to the
5.30 + "messages" property.
5.31 +
5.32 + When a new message is added, the detector sends it to all the users on
5.33 + the "nosy" list for the issue that are not already on the "recipients"
5.34 + list of the message.
5.35 +
5.36 + Those users are then appended to the "recipients" property on the
5.37 + message, so multiple copies of a message are never sent to the same
5.38 + user.
5.39 +
5.40 + The journal recorded by the hyperdatabase on the "recipients" property
5.41 + then provides a log of when the message was sent to whom.
5.42 + '''
5.43 + # send a copy of all new messages to the nosy list
5.44 + for msgid in determineNewMessages(cl, nodeid, oldvalues):
5.45 + try:
5.46 + cl.nosymessage(nodeid, msgid, oldvalues)
5.47 + except roundupdb.MessageSendError, message:
5.48 + raise roundupdb.DetectorError, message
5.49 +
5.50 +def determineNewMessages(cl, nodeid, oldvalues):
5.51 + ''' Figure a list of the messages that are being added to the given
5.52 + node in this transaction.
5.53 + '''
5.54 + messages = []
5.55 + if oldvalues is None:
5.56 + # the action was a create, so use all the messages in the create
5.57 + messages = cl.get(nodeid, 'messages')
5.58 + elif oldvalues.has_key('messages'):
5.59 + # the action was a set (so adding new messages to an existing issue)
5.60 + m = {}
5.61 + for msgid in oldvalues['messages']:
5.62 + m[msgid] = 1
5.63 + messages = []
5.64 + # figure which of the messages now on the issue weren't there before
5.65 + for msgid in cl.get(nodeid, 'messages'):
5.66 + if not m.has_key(msgid):
5.67 + messages.append(msgid)
5.68 + return messages
5.69 +
5.70 +def updatenosy(db, cl, nodeid, newvalues):
5.71 + '''Update the nosy list for changes to the assignedto
5.72 + '''
5.73 + # nodeid will be None if this is a new node
5.74 + current_nosy = set()
5.75 + if nodeid is None:
5.76 + ok = ('new', 'yes')
5.77 + else:
5.78 + ok = ('yes',)
5.79 + # old node, get the current values from the node if they haven't
5.80 + # changed
5.81 + if not newvalues.has_key('nosy'):
5.82 + nosy = cl.get(nodeid, 'nosy')
5.83 + for value in nosy:
5.84 + current_nosy.add(value)
5.85 +
5.86 + # if the nosy list changed in this transaction, init from the new value
5.87 + if newvalues.has_key('nosy'):
5.88 + nosy = newvalues.get('nosy', [])
5.89 + for value in nosy:
5.90 + if not db.hasnode('user', value):
5.91 + continue
5.92 + current_nosy.add(value)
5.93 +
5.94 + new_nosy = set(current_nosy)
5.95 +
5.96 + # add assignedto(s) to the nosy list
5.97 + if newvalues.has_key('assignedto') and newvalues['assignedto'] is not None:
5.98 + propdef = cl.getprops()
5.99 + if isinstance(propdef['assignedto'], hyperdb.Link):
5.100 + assignedto_ids = [newvalues['assignedto']]
5.101 + elif isinstance(propdef['assignedto'], hyperdb.Multilink):
5.102 + assignedto_ids = newvalues['assignedto']
5.103 + for assignedto_id in assignedto_ids:
5.104 + new_nosy.add(assignedto_id)
5.105 +
5.106 + # see if there's any new messages - if so, possibly add the author and
5.107 + # recipient to the nosy
5.108 + if newvalues.has_key('messages'):
5.109 + if nodeid is None:
5.110 + ok = ('new', 'yes')
5.111 + messages = newvalues['messages']
5.112 + else:
5.113 + ok = ('yes',)
5.114 + # figure which of the messages now on the issue weren't
5.115 + oldmessages = cl.get(nodeid, 'messages')
5.116 + messages = []
5.117 + for msgid in newvalues['messages']:
5.118 + if msgid not in oldmessages:
5.119 + messages.append(msgid)
5.120 +
5.121 + # configs for nosy modifications
5.122 + add_author = getattr(db.config, 'ADD_AUTHOR_TO_NOSY', 'new')
5.123 + add_recips = getattr(db.config, 'ADD_RECIPIENTS_TO_NOSY', 'new')
5.124 +
5.125 + # now for each new message:
5.126 + msg = db.msg
5.127 + for msgid in messages:
5.128 + if add_author in ok:
5.129 + authid = msg.get(msgid, 'author')
5.130 + new_nosy.add(authid)
5.131 +
5.132 + # add on the recipients of the message
5.133 + if add_recips in ok:
5.134 + for recipient in msg.get(msgid, 'recipients'):
5.135 + new_nosy.add(recipient)
5.136 +
5.137 + if current_nosy != new_nosy:
5.138 + # that's it, save off the new nosy list
5.139 + newvalues['nosy'] = list(new_nosy)
5.140 +
5.141 +def init(db):
5.142 + db.issue.react('create', nosyreaction)
5.143 + db.issue.react('set', nosyreaction)
5.144 + db.issue.audit('create', updatenosy)
5.145 + db.issue.audit('set', updatenosy)
5.146 +
5.147 +# vim: set filetype=python ts=4 sw=4 et si
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/themes/mercurialroundup/detectors/statusauditor.py Mon Jun 07 01:14:02 2010 +0200
6.3 @@ -0,0 +1,85 @@
6.4 +# Copyright (c) 2002 ekit.com Inc (http://www.ekit-inc.com/)
6.5 +#
6.6 +# Permission is hereby granted, free of charge, to any person obtaining a copy
6.7 +# of this software and associated documentation files (the "Software"), to deal
6.8 +# in the Software without restriction, including without limitation the rights
6.9 +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
6.10 +# copies of the Software, and to permit persons to whom the Software is
6.11 +# furnished to do so, subject to the following conditions:
6.12 +#
6.13 +# The above copyright notice and this permission notice shall be included in
6.14 +# all copies or substantial portions of the Software.
6.15 +#
6.16 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6.17 +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6.18 +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6.19 +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
6.20 +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
6.21 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
6.22 +# SOFTWARE.
6.23 +#
6.24 +#$Id: statusauditor.py,v 1.5 2004-03-27 00:01:48 richard Exp $
6.25 +
6.26 +def chatty(db, cl, nodeid, newvalues):
6.27 + ''' If the issue is currently 'unread', 'resolved', 'done-cbb' or None,
6.28 + then set it to 'chatting'
6.29 + '''
6.30 + # don't fire if there's no new message (ie. chat)
6.31 + if not newvalues.has_key('messages'):
6.32 + return
6.33 + if newvalues['messages'] == cl.get(nodeid, 'messages'):
6.34 + return
6.35 +
6.36 + # get the chatting state ID
6.37 + try:
6.38 + chatting_id = db.status.lookup('chatting')
6.39 + except KeyError:
6.40 + # no chatting state, ignore all this stuff
6.41 + return
6.42 +
6.43 + # get the current value
6.44 + current_status = cl.get(nodeid, 'status')
6.45 +
6.46 + # see if there's an explicit change in this transaction
6.47 + if newvalues.has_key('status'):
6.48 + # yep, skip
6.49 + return
6.50 +
6.51 + # determine the id of 'unread', 'resolved' and 'chatting'
6.52 + fromstates = []
6.53 + for state in 'unread resolved done-cbb'.split():
6.54 + try:
6.55 + fromstates.append(db.status.lookup(state))
6.56 + except KeyError:
6.57 + pass
6.58 +
6.59 + # ok, there's no explicit change, so check if we are in a state that
6.60 + # should be changed
6.61 + if current_status in fromstates + [None]:
6.62 + # yep, we're now chatting
6.63 + newvalues['status'] = chatting_id
6.64 +
6.65 +
6.66 +def presetunread(db, cl, nodeid, newvalues):
6.67 + ''' Make sure the status is set on new issues
6.68 + '''
6.69 + if newvalues.has_key('status') and newvalues['status']:
6.70 + return
6.71 +
6.72 + # get the unread state ID
6.73 + try:
6.74 + unread_id = db.status.lookup('unread')
6.75 + except KeyError:
6.76 + # no unread state, ignore all this stuff
6.77 + return
6.78 +
6.79 + # ok, do it
6.80 + newvalues['status'] = unread_id
6.81 +
6.82 +
6.83 +def init(db):
6.84 + # fire before changes are made
6.85 + db.issue.audit('set', chatty)
6.86 + db.issue.audit('create', presetunread)
6.87 +
6.88 +# vim: set filetype=python ts=4 sw=4 et si
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/themes/mercurialroundup/detectors/userauditor.py Mon Jun 07 01:14:02 2010 +0200
7.3 @@ -0,0 +1,94 @@
7.4 +# Copyright (c) 2003 Richard Jones (richard@mechanicalcat.net)
7.5 +#
7.6 +# Permission is hereby granted, free of charge, to any person obtaining a copy
7.7 +# of this software and associated documentation files (the "Software"), to deal
7.8 +# in the Software without restriction, including without limitation the rights
7.9 +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7.10 +# copies of the Software, and to permit persons to whom the Software is
7.11 +# furnished to do so, subject to the following conditions:
7.12 +#
7.13 +# The above copyright notice and this permission notice shall be included in
7.14 +# all copies or substantial portions of the Software.
7.15 +#
7.16 +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7.17 +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
7.18 +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
7.19 +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7.20 +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
7.21 +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
7.22 +# SOFTWARE.
7.23 +#
7.24 +#$Id: userauditor.py,v 1.9 2007-09-12 21:11:13 jpend Exp $
7.25 +
7.26 +import re
7.27 +
7.28 +# regular expression thanks to: http://www.regular-expressions.info/email.html
7.29 +# this is the "99.99% solution for syntax only".
7.30 +email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))")
7.31 +email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
7.32 +email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
7.33 +
7.34 +def valid_address(address):
7.35 + ''' If we see an @-symbol in the address then check against the full
7.36 + RFC syntax. Otherwise it is a local-only address so only check
7.37 + the local part of the RFC syntax.
7.38 + '''
7.39 + if '@' in address:
7.40 + return email_rfc.match(address)
7.41 + else:
7.42 + return email_local.match(address)
7.43 +
7.44 +def get_addresses(user):
7.45 + ''' iterate over all known addresses in a newvalues dict
7.46 + this takes of the address/alterate_addresses handling
7.47 + '''
7.48 + if user.has_key('address'):
7.49 + yield user['address']
7.50 + if user.get('alternate_addresses', None):
7.51 + for address in user['alternate_addresses'].split('\n'):
7.52 + yield address
7.53 +
7.54 +def audit_user_fields(db, cl, nodeid, newvalues):
7.55 + ''' Make sure user properties are valid.
7.56 +
7.57 + - email address is syntactically valid
7.58 + - email address is unique
7.59 + - roles specified exist
7.60 + - timezone is valid
7.61 + '''
7.62 +
7.63 + for address in get_addresses(newvalues):
7.64 + if not valid_address(address):
7.65 + raise ValueError, 'Email address syntax is invalid'
7.66 +
7.67 + check_main = db.user.stringFind(address=address)
7.68 + # make sure none of the alts are owned by anyone other than us (x!=nodeid)
7.69 + check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid]
7.70 + if check_main or check_alts:
7.71 + raise ValueError, 'Email address %s already in use' % address
7.72 +
7.73 + for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]:
7.74 + if rolename and not db.security.role.has_key(rolename):
7.75 + raise ValueError, 'Role "%s" does not exist'%rolename
7.76 +
7.77 + tz = newvalues.get('timezone', None)
7.78 + if tz:
7.79 + # if they set a new timezone validate the timezone by attempting to
7.80 + # use it before we store it to the db.
7.81 + import roundup.date
7.82 + import datetime
7.83 + try:
7.84 + TZ = roundup.date.get_timezone(tz)
7.85 + dt = datetime.datetime.now()
7.86 + local = TZ.localize(dt).utctimetuple()
7.87 + except IOError:
7.88 + raise ValueError, 'Timezone "%s" does not exist' % tz
7.89 + except ValueError:
7.90 + raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz
7.91 +
7.92 +def init(db):
7.93 + # fire before changes are made
7.94 + db.user.audit('set', audit_user_fields)
7.95 + db.user.audit('create', audit_user_fields)
7.96 +
7.97 +# vim: sts=4 sw=4 et si
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/themes/mercurialroundup/extensions/README.txt Mon Jun 07 01:14:02 2010 +0200
8.3 @@ -0,0 +1,6 @@
8.4 +This directory is for tracker extensions:
8.5 +
8.6 +- CGI Actions
8.7 +- Templating functions
8.8 +
8.9 +See the customisation doc for more information.
9.1 --- a/themes/mercurialroundup/html/page.html Sun Jun 06 16:20:14 2010 +0200
9.2 +++ b/themes/mercurialroundup/html/page.html Mon Jun 07 01:14:02 2010 +0200
9.3 @@ -4,6 +4,7 @@
9.4 <html>
9.5 <head>
9.6 <title metal:define-slot="head_title">title goes here</title>
9.7 +<link rel="stylesheet" type="text/css" href="@@file/style-mercurialweb.css">
9.8 <link rel="stylesheet" type="text/css" href="@@file/style.css">
9.9 <meta http-equiv="Content-Type"
9.10 tal:attributes="content string:text/html;; charset=${request/client/charset}" />
9.11 @@ -12,9 +13,7 @@
9.12 <metal:x define-slot="more-javascript" />
9.13
9.14 </head>
9.15 -<body class="body">
9.16 -
9.17 -<table class="body"
9.18 +<body class="body"
9.19 tal:define="
9.20 kw_edit python:request.user.hasPermission('Edit', 'keyword');
9.21 kw_create python:request.user.hasPermission('Create', 'keyword');
9.22 @@ -25,27 +24,58 @@
9.23 "
9.24 >
9.25
9.26 -<tr>
9.27 - <td class="page-header-left"> </td>
9.28 - <td class="page-header-top">
9.29 - <div id="searchbox">
9.30 - <form method="GET" action="issue">
9.31 - <input type="hidden" name="@columns"
9.32 - tal:attributes="value columns_showall"
9.33 - value="id,activity,title,creator,assignedto,status"/>
9.34 - <input type="hidden" name="@sort" value="activity"/>
9.35 - <input type="hidden" name="@group" value="priority"/>
9.36 - <input id="search-text" name="@search_text" size="10"
9.37 - tal:attributes="value request/search_text | default" />
9.38 - <input type="submit" id="submit" name="submit" value="Search"
9.39 - i18n:attributes="value" />
9.40 - </form>
9.41 - </div>
9.42 - <div id="body-title">
9.43 - <h2><span metal:define-slot="body_title">body title</span></h2>
9.44 - </div>
9.45 - </td>
9.46 -</tr>
9.47 +<div id="header">
9.48 + <div id="logo"><a href="#" tal:attributes="href request/base"><img src="@@file/mercurial-logo.png" alt="Mercurial logo" /></a></div>
9.49 + <div class="controls">
9.50 + <ul id="navibar">
9.51 + <li tal:attributes="class python:request.form.getvalue('@template') is None and 'current'" class=""
9.52 + ><a href="#" tal:attributes="href request/base">Home</a></li
9.53 + ><li tal:condition="python:request.user.hasPermission('Create', 'issue')"
9.54 + tal:attributes="class python:request.form.getvalue('@template') == 'item' and 'current'" class=""
9.55 + ><a href="issue?@template=item" i18n:translate="">New issue</a></li
9.56 + ><li tal:attributes="class python:request.form.getvalue('@template') == 'search' and 'current'" class=""
9.57 + ><a href="issue?@template=search" i18n:translate="">Search</a></li
9.58 + ><li tal:condition="python:request.user.username=='anonymous' and request.user.hasPermission('Register', 'user')"
9.59 + tal:attributes="class python:request.form.getvalue('@template') == 'register' and 'current'" class=""
9.60 + ><a href="user?@template=register" i18n:translate="">Register</a></li
9.61 + ><li tal:condition="python:request.user.username != 'anonymous'"
9.62 + i18n:translate=""><a href="user" i18n:name="user"
9.63 + tal:replace="python:request.user.username.plain(escape=1)">username</a></li
9.64 + ><li tal:condition="python:request.user.hasPermission('View', 'issue')"
9.65 + ><form method="POST" tal:attributes="action request/base"><span class="container">
9.66 + <a href="#"
9.67 + tal:attributes="href python:request.indexargs_url('issue', {
9.68 + '@sort': '-activity',
9.69 + '@group': 'priority',
9.70 + '@filter': 'status',
9.71 + '@columns': columns_showall,
9.72 + '@search_text': '',
9.73 + 'status': status_notresolved,
9.74 + '@dispname': i18n.gettext('Show All'),
9.75 + })"
9.76 + i18n:translate="">Browse</a></span
9.77 + ><input type="hidden" name="@type" value="issue"
9.78 + /><input type="hidden" name="@action" value="show"
9.79 + /></form></li
9.80 + ><li><form id="searchform" action="issue"><span class="container">
9.81 + <span class="hint" i18n:translate="">Search</span> <input name="@search_text" id="searchinput" type="text" size="20"
9.82 + tal:attributes="value request/search_text | default" />
9.83 + </span>
9.84 + <input type="hidden" name="@columns"
9.85 + tal:attributes="value columns_showall"
9.86 + value="id,activity,title,creator,assignedto,status" />
9.87 + <input type="hidden" name="@sort" value="activity" />
9.88 + <input type="hidden" name="@group" value="priority" />
9.89 + </form>
9.90 + </li>
9.91 + </ul>
9.92 + </div>
9.93 + <div id="pageline"></div>
9.94 +</div>
9.95 +
9.96 +<h2><span metal:define-slot="body_title">body title</span></h2>
9.97 +
9.98 +<table class="body">
9.99
9.100 <tr>
9.101 <td rowspan="2" valign="top" class="sidebar">
9.102 @@ -59,45 +89,6 @@
9.103 </tal:block>
9.104 </p>
9.105
9.106 - <form method="POST" tal:attributes="action request/base">
9.107 - <p class="classblock"
9.108 - tal:condition="python:request.user.hasPermission('View', 'issue')">
9.109 - <b i18n:translate="">Issues</b><br>
9.110 - <span tal:condition="python:request.user.hasPermission('Create', 'issue')">
9.111 - <a href="issue?@template=item" i18n:translate="">Create New</a><br>
9.112 - </span>
9.113 - <a href="#"
9.114 - tal:attributes="href python:request.indexargs_url('issue', {
9.115 - '@sort': '-activity',
9.116 - '@group': 'priority',
9.117 - '@filter': 'status,assignedto',
9.118 - '@columns': columns,
9.119 - '@search_text': '',
9.120 - 'status': status_notresolved,
9.121 - 'assignedto': '-1',
9.122 - '@dispname': i18n.gettext('Show Unassigned'),
9.123 - })"
9.124 - i18n:translate="">Show Unassigned</a><br>
9.125 - <a href="#"
9.126 - tal:attributes="href python:request.indexargs_url('issue', {
9.127 - '@sort': '-activity',
9.128 - '@group': 'priority',
9.129 - '@filter': 'status',
9.130 - '@columns': columns_showall,
9.131 - '@search_text': '',
9.132 - 'status': status_notresolved,
9.133 - '@dispname': i18n.gettext('Show All'),
9.134 - })"
9.135 - i18n:translate="">Show All</a><br>
9.136 - <a href="issue?@template=search" i18n:translate="">Search</a><br>
9.137 - <input type="submit" class="form-small" value="Show issue:"
9.138 - i18n:attributes="value"><input class="form-small" size="4"
9.139 - type="text" name="@number">
9.140 - <input type="hidden" name="@type" value="issue">
9.141 - <input type="hidden" name="@action" value="show">
9.142 - </p>
9.143 - </form>
9.144 -
9.145 <p class="classblock"
9.146 tal:condition="python:kw_edit or kw_create">
9.147 <b i18n:translate="">Keywords</b><br>
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/themes/mercurialroundup/html/style-mercurialweb.css Mon Jun 07 01:14:02 2010 +0200
10.3 @@ -0,0 +1,255 @@
10.4 +/* style-mercurialweb.css - stylesheets resembling the MercurialWikiTheme styles
10.5 +
10.6 +Copyright (c) 2010 Paul Boddie <paul@boddie.org.uk>
10.7 +Copyright (c) 2001, 2002, 2003 by Juergen Hermann
10.8 +*/
10.9 +
10.10 +/* content styles */
10.11 +
10.12 +body {
10.13 + padding: 0;
10.14 + margin: 0;
10.15 + border: 0;
10.16 +
10.17 + /* Styling similar to the main site. */
10.18 +
10.19 + font-family: Helvetica, Verdana, Arial, sans-serif;
10.20 + color: #111;
10.21 + margin: 0 5em;
10.22 +}
10.23 +
10.24 +a, img {
10.25 + border: 0;
10.26 +}
10.27 +
10.28 +a:link, a:visited { color: #00b5f1; text-decoration: none; }
10.29 +a:link:hover, a:link:active, a:link:focus,
10.30 +a:visited:hover, a:visited:active, a:visited:focus { text-decoration: underline; }
10.31 +
10.32 +input, select {
10.33 +
10.34 + /* Styling similar to the main site. */
10.35 +
10.36 + font-family: Helvetica, Arial, sans-serif;
10.37 + font-size: 0.8571em;
10.38 +}
10.39 +
10.40 +/* Table styling. */
10.41 +
10.42 +table
10.43 +{
10.44 + margin: 1em 0;
10.45 + border-collapse: collapse;
10.46 +}
10.47 +
10.48 +th {
10.49 + text-align: left;
10.50 +}
10.51 +
10.52 +th a:link, th a:visited {
10.53 + color: #111;
10.54 +}
10.55 +
10.56 +th, td {
10.57 + padding: 0.4em 0.25em;
10.58 +}
10.59 +
10.60 +td p {
10.61 + margin: 0;
10.62 + padding: 0;
10.63 +}
10.64 +
10.65 +/* Styling of headings from the main site. */
10.66 +
10.67 +h1 { font-size: 2em; }
10.68 +h2 { font-size: 1.6em; }
10.69 +h3 { font-size: 1.3em; }
10.70 +
10.71 +/* Repository information. */
10.72 +
10.73 +span.tag {
10.74 + background: #f1b500;
10.75 + padding: 0.25em 0.5em;
10.76 +}
10.77 +
10.78 +span.branch {
10.79 + background: #b5f1b5;
10.80 + padding: 0.25em 0.5em;
10.81 +}
10.82 +
10.83 +span.inbranch {
10.84 + background: #b5b5b5;
10.85 + padding: 0.25em 0.5em;
10.86 +}
10.87 +
10.88 +/* Navigational and editing controls. */
10.89 +
10.90 +@media print {
10.91 + #header {
10.92 + display: none;
10.93 + }
10.94 +}
10.95 +
10.96 +.controls {
10.97 + float: right;
10.98 + text-align: right;
10.99 +}
10.100 +
10.101 +#navibar {
10.102 + display: inline-block;
10.103 + margin: 17px 0 2px 0;
10.104 + padding: 0;
10.105 + vertical-align: bottom;
10.106 +}
10.107 +
10.108 +#navibar li {
10.109 + display: inline;
10.110 + margin: 0;
10.111 + padding: 0;
10.112 +}
10.113 +
10.114 +#navibar li form {
10.115 + display: inline;
10.116 +}
10.117 +
10.118 +#navibar a, #navibar li.current span, .navigation a {
10.119 + color: #fff;
10.120 + text-decoration: none;
10.121 +}
10.122 +
10.123 +#navibar a {
10.124 + background: #999;
10.125 +}
10.126 +
10.127 +.navigation a {
10.128 + background: #ccc;
10.129 +}
10.130 +
10.131 +#navibar a, #navibar li.current span {
10.132 +
10.133 + /* Need a block to redefine the height. */
10.134 +
10.135 + display: inline-block;
10.136 + height: 42px;
10.137 + line-height: 42px;
10.138 +
10.139 + margin: 0;
10.140 + padding: 0 16px;
10.141 +}
10.142 +
10.143 +.navigation a {
10.144 + padding: 0.25em 0.5em;
10.145 +}
10.146 +
10.147 +#navibar a:hover, #navibar a:focus, #navibar li.current a, #navibar li.current span,
10.148 +.navigation a:hover, .navigation a:focus {
10.149 + background: #00b5f1;
10.150 +}
10.151 +
10.152 +#navibar a:hover, #navibar a:focus, #navibar li.current a,
10.153 +.navigation a:hover, .navigation a:focus {
10.154 + text-decoration: none;
10.155 +}
10.156 +
10.157 +/* Other elements. */
10.158 +
10.159 +#logo {
10.160 + float: left;
10.161 + margin: 0;
10.162 + padding: 0;
10.163 +
10.164 + /* For text only logo */
10.165 +
10.166 + font-size: larger;
10.167 + font-weight: bold;
10.168 +}
10.169 +
10.170 +#logo img {
10.171 + vertical-align: bottom;
10.172 +}
10.173 +
10.174 +#logo a {
10.175 + color: black;
10.176 + text-decoration: none;
10.177 +}
10.178 +
10.179 +#navibar form span.container {
10.180 + position: relative;
10.181 + display: inline-block;
10.182 +
10.183 + /* Margin and padding correspond to the navibar settings. */
10.184 +
10.185 + margin: 0;
10.186 + background: #999;
10.187 +
10.188 + /* Height settings correspond to navibar list entries. */
10.189 +
10.190 + height: 42px;
10.191 + line-height: 42px;
10.192 +}
10.193 +
10.194 +form#searchform span.container {
10.195 +
10.196 + /* Margin and padding correspond to the navibar settings. */
10.197 +
10.198 + padding: 0 16px;
10.199 +}
10.200 +
10.201 +#searchform span.container span.hint {
10.202 + display: none;
10.203 +}
10.204 +
10.205 +#searchform span.container:hover span.hint {
10.206 + display: block;
10.207 + position: absolute;
10.208 + top: 42px;
10.209 + left: 16px;
10.210 +
10.211 + padding: 0 16px;
10.212 +
10.213 + background: #00b5f1;
10.214 + color: #fff;
10.215 +}
10.216 +
10.217 +#searchform input {
10.218 + vertical-align: middle;
10.219 +}
10.220 +
10.221 +#searchform label {
10.222 + font-size: smaller;
10.223 + color: #fff;
10.224 +}
10.225 +
10.226 +#pageline, .pageline {
10.227 +
10.228 + /* Prevent mixing of header and content elements. */
10.229 +
10.230 + clear: both;
10.231 + margin: 0;
10.232 + padding: 0;
10.233 + border-bottom: 1px solid #ccc;
10.234 +}
10.235 +
10.236 +#credits {
10.237 + float: right;
10.238 +
10.239 + /* Styling similar to the main site. */
10.240 +
10.241 + font-family: Verdana, Helvetica, Arial, sans-serif;
10.242 + font-size: .6428em;
10.243 + padding: 10px 25px;
10.244 +}
10.245 +
10.246 +#credits li {
10.247 + display: inline;
10.248 + padding: 0 2px;
10.249 + margin: 0 4px;
10.250 +}
10.251 +
10.252 +#credits img {
10.253 + vertical-align: middle;
10.254 +}
10.255 +
10.256 +#credits a {
10.257 + text-decoration: none;
10.258 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/themes/mercurialroundup/initial_data.py Mon Jun 07 01:14:02 2010 +0200
12.3 @@ -0,0 +1,32 @@
12.4 +#
12.5 +# TRACKER INITIAL PRIORITY AND STATUS VALUES
12.6 +#
12.7 +pri = db.getclass('priority')
12.8 +pri.create(name=''"critical", order="1")
12.9 +pri.create(name=''"urgent", order="2")
12.10 +pri.create(name=''"bug", order="3")
12.11 +pri.create(name=''"feature", order="4")
12.12 +pri.create(name=''"wish", order="5")
12.13 +
12.14 +stat = db.getclass('status')
12.15 +stat.create(name=''"unread", order="1")
12.16 +stat.create(name=''"deferred", order="2")
12.17 +stat.create(name=''"chatting", order="3")
12.18 +stat.create(name=''"need-eg", order="4")
12.19 +stat.create(name=''"in-progress", order="5")
12.20 +stat.create(name=''"testing", order="6")
12.21 +stat.create(name=''"done-cbb", order="7")
12.22 +stat.create(name=''"resolved", order="8")
12.23 +
12.24 +# create the two default users
12.25 +user = db.getclass('user')
12.26 +user.create(username="admin", password=adminpw,
12.27 + address=admin_email, roles='Admin')
12.28 +user.create(username="anonymous", roles='Anonymous')
12.29 +
12.30 +# add any additional database creation steps here - but only if you
12.31 +# haven't initialised the database with the admin "initialise" command
12.32 +
12.33 +
12.34 +# vim: set filetype=python sts=4 sw=4 et si
12.35 +#SHA: b1da2e72a7fe9f26086f243eb744135b085101d9
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/themes/mercurialroundup/schema.py Mon Jun 07 01:14:02 2010 +0200
13.3 @@ -0,0 +1,176 @@
13.4 +
13.5 +#
13.6 +# TRACKER SCHEMA
13.7 +#
13.8 +
13.9 +# Class automatically gets these properties:
13.10 +# creation = Date()
13.11 +# activity = Date()
13.12 +# creator = Link('user')
13.13 +# actor = Link('user')
13.14 +
13.15 +# Priorities
13.16 +pri = Class(db, "priority",
13.17 + name=String(),
13.18 + order=Number())
13.19 +pri.setkey("name")
13.20 +
13.21 +# Statuses
13.22 +stat = Class(db, "status",
13.23 + name=String(),
13.24 + order=Number())
13.25 +stat.setkey("name")
13.26 +
13.27 +# Keywords
13.28 +keyword = Class(db, "keyword",
13.29 + name=String())
13.30 +keyword.setkey("name")
13.31 +
13.32 +# User-defined saved searches
13.33 +query = Class(db, "query",
13.34 + klass=String(),
13.35 + name=String(),
13.36 + url=String(),
13.37 + private_for=Link('user'))
13.38 +
13.39 +# add any additional database schema configuration here
13.40 +
13.41 +user = Class(db, "user",
13.42 + username=String(),
13.43 + password=Password(),
13.44 + address=String(),
13.45 + realname=String(),
13.46 + phone=String(),
13.47 + organisation=String(),
13.48 + alternate_addresses=String(),
13.49 + queries=Multilink('query'),
13.50 + roles=String(), # comma-separated string of Role names
13.51 + timezone=String())
13.52 +user.setkey("username")
13.53 +db.security.addPermission(name='Register', klass='user',
13.54 + description='User is allowed to register new user')
13.55 +
13.56 +# FileClass automatically gets this property in addition to the Class ones:
13.57 +# content = String() [saved to disk in <tracker home>/db/files/]
13.58 +# type = String() [MIME type of the content, default 'text/plain']
13.59 +msg = FileClass(db, "msg",
13.60 + author=Link("user", do_journal='no'),
13.61 + recipients=Multilink("user", do_journal='no'),
13.62 + date=Date(),
13.63 + summary=String(),
13.64 + files=Multilink("file"),
13.65 + messageid=String(),
13.66 + inreplyto=String())
13.67 +
13.68 +file = FileClass(db, "file",
13.69 + name=String())
13.70 +
13.71 +# IssueClass automatically gets these properties in addition to the Class ones:
13.72 +# title = String()
13.73 +# messages = Multilink("msg")
13.74 +# files = Multilink("file")
13.75 +# nosy = Multilink("user")
13.76 +# superseder = Multilink("issue")
13.77 +issue = IssueClass(db, "issue",
13.78 + assignedto=Link("user"),
13.79 + keyword=Multilink("keyword"),
13.80 + priority=Link("priority"),
13.81 + status=Link("status"))
13.82 +
13.83 +#
13.84 +# TRACKER SECURITY SETTINGS
13.85 +#
13.86 +# See the configuration and customisation document for information
13.87 +# about security setup.
13.88 +
13.89 +#
13.90 +# REGULAR USERS
13.91 +#
13.92 +# Give the regular users access to the web and email interface
13.93 +db.security.addPermissionToRole('User', 'Web Access')
13.94 +db.security.addPermissionToRole('User', 'Email Access')
13.95 +
13.96 +# Assign the access and edit Permissions for issue, file and message
13.97 +# to regular users now
13.98 +for cl in 'issue', 'file', 'msg', 'keyword':
13.99 + db.security.addPermissionToRole('User', 'View', cl)
13.100 + db.security.addPermissionToRole('User', 'Edit', cl)
13.101 + db.security.addPermissionToRole('User', 'Create', cl)
13.102 +for cl in 'priority', 'status':
13.103 + db.security.addPermissionToRole('User', 'View', cl)
13.104 +
13.105 +# May users view other user information? Comment these lines out
13.106 +# if you don't want them to
13.107 +db.security.addPermissionToRole('User', 'View', 'user')
13.108 +
13.109 +# Users should be able to edit their own details -- this permission is
13.110 +# limited to only the situation where the Viewed or Edited item is their own.
13.111 +def own_record(db, userid, itemid):
13.112 + '''Determine whether the userid matches the item being accessed.'''
13.113 + return userid == itemid
13.114 +p = db.security.addPermission(name='View', klass='user', check=own_record,
13.115 + description="User is allowed to view their own user details")
13.116 +db.security.addPermissionToRole('User', p)
13.117 +p = db.security.addPermission(name='Edit', klass='user', check=own_record,
13.118 + properties=('username', 'password', 'address', 'realname', 'phone',
13.119 + 'organisation', 'alternate_addresses', 'queries', 'timezone'),
13.120 + description="User is allowed to edit their own user details")
13.121 +db.security.addPermissionToRole('User', p)
13.122 +
13.123 +# Users should be able to edit and view their own queries. They should also
13.124 +# be able to view any marked as not private. They should not be able to
13.125 +# edit others' queries, even if they're not private
13.126 +def view_query(db, userid, itemid):
13.127 + private_for = db.query.get(itemid, 'private_for')
13.128 + if not private_for: return True
13.129 + return userid == private_for
13.130 +def edit_query(db, userid, itemid):
13.131 + return userid == db.query.get(itemid, 'creator')
13.132 +p = db.security.addPermission(name='View', klass='query', check=view_query,
13.133 + description="User is allowed to view their own and public queries")
13.134 +db.security.addPermissionToRole('User', p)
13.135 +p = db.security.addPermission(name='Edit', klass='query', check=edit_query,
13.136 + description="User is allowed to edit their queries")
13.137 +db.security.addPermissionToRole('User', p)
13.138 +p = db.security.addPermission(name='Retire', klass='query', check=edit_query,
13.139 + description="User is allowed to retire their queries")
13.140 +db.security.addPermissionToRole('User', p)
13.141 +p = db.security.addPermission(name='Create', klass='query',
13.142 + description="User is allowed to create queries")
13.143 +db.security.addPermissionToRole('User', p)
13.144 +
13.145 +
13.146 +#
13.147 +# ANONYMOUS USER PERMISSIONS
13.148 +#
13.149 +# Let anonymous users access the web interface. Note that almost all
13.150 +# trackers will need this Permission. The only situation where it's not
13.151 +# required is in a tracker that uses an HTTP Basic Authenticated front-end.
13.152 +db.security.addPermissionToRole('Anonymous', 'Web Access')
13.153 +
13.154 +# Let anonymous users access the email interface (note that this implies
13.155 +# that they will be registered automatically, hence they will need the
13.156 +# "Create" user Permission below)
13.157 +# This is disabled by default to stop spam from auto-registering users on
13.158 +# public trackers.
13.159 +#db.security.addPermissionToRole('Anonymous', 'Email Access')
13.160 +
13.161 +# Assign the appropriate permissions to the anonymous user's Anonymous
13.162 +# Role. Choices here are:
13.163 +# - Allow anonymous users to register
13.164 +db.security.addPermissionToRole('Anonymous', 'Register', 'user')
13.165 +
13.166 +# Allow anonymous users access to view issues (and the related, linked
13.167 +# information)
13.168 +for cl in 'issue', 'file', 'msg', 'keyword', 'priority', 'status':
13.169 + db.security.addPermissionToRole('Anonymous', 'View', cl)
13.170 +
13.171 +# [OPTIONAL]
13.172 +# Allow anonymous users access to create or edit "issue" items (and the
13.173 +# related file and message items)
13.174 +#for cl in 'issue', 'file', 'msg':
13.175 +# db.security.addPermissionToRole('Anonymous', 'Create', cl)
13.176 +# db.security.addPermissionToRole('Anonymous', 'Edit', cl)
13.177 +
13.178 +
13.179 +# vim: set filetype=python sts=4 sw=4 et si :