[Python-checkins] r60862 - in tracker/instances/jobs: detectors/sendmail.py detectors/statusauditor.py html/offer.item.html html/page.html schema.py

martin.v.loewis python-checkins at python.org
Sat Feb 16 19:05:17 CET 2008


Author: martin.v.loewis
Date: Sat Feb 16 19:05:17 2008
New Revision: 60862

Modified:
   tracker/instances/jobs/detectors/sendmail.py
   tracker/instances/jobs/detectors/statusauditor.py
   tracker/instances/jobs/html/offer.item.html
   tracker/instances/jobs/html/page.html
   tracker/instances/jobs/schema.py
Log:
Implement all known requirements.


Modified: tracker/instances/jobs/detectors/sendmail.py
==============================================================================
--- tracker/instances/jobs/detectors/sendmail.py	(original)
+++ tracker/instances/jobs/detectors/sendmail.py	Sat Feb 16 19:05:17 2008
@@ -186,5 +186,6 @@
 
 
 def init(db):
+    return
     db.offer.react('set', sendmail)
     db.offer.react('create', sendmail)

Modified: tracker/instances/jobs/detectors/statusauditor.py
==============================================================================
--- tracker/instances/jobs/detectors/statusauditor.py	(original)
+++ tracker/instances/jobs/detectors/statusauditor.py	Sat Feb 16 19:05:17 2008
@@ -1,95 +1,75 @@
+import os, roundup.date
+
 def init_status(db, cl, nodeid, newvalues):
     """ Make sure the status is set on new offers"""
 
     if newvalues.has_key('status') and newvalues['status']:
+        if newvalues['status'] == posted:
+            raise ValueError, "You can only set the offer to submitted, not posted"
         return
 
     new_id = db.status.lookup('submitted')
     newvalues['status'] = new_id
 
 
-def block_resolution(db, cl, nodeid, newvalues):
-    """ If the offer has blockers, don't allow it to be resolved."""
-
-    if nodeid is None:
-        dependencies = []
-    else:
-        dependencies = cl.get(nodeid, 'dependencies')
-    dependencies = newvalues.get('dependencies', dependencies)
-
-    # don't do anything if there's no blockers or the status hasn't
-    # changed
-    if not dependencies or not newvalues.has_key('status'):
+def audit_status(db, cl, nodeid, newvalues):
+    "Prevent regular users from posting their offers themselves."
+    user = db.getuid()
+    if newvalues.get('status') != posted:
         return
-
-    # format the info
-    u = db.config.TRACKER_WEB
-    s = ', '.join(['<a href="%soffer%s">%s</a>'%(u,id,id) for id in dependencies])
-    if len(dependencies) == 1:
-        s = 'offer %s is'%s
+    if db.user.get(user, 'roles').lower().find('editor') != -1:
+        # Ok if an editor posted it; set the posting date
+        newvalues['posted'] = roundup.date.Date()
     else:
-        s = 'offers %s are'%s
-
-    # ok, see if we're trying to resolve
-    if newvalues.get('status') and newvalues['status'] == db.status.lookup('closed'):
-        raise ValueError, "This offer can't be closed until %s closed."%s
-
-
-def resolve(db, cl, nodeid, newvalues):
-    """Make sure status, resolution, and superseder values match."""
-
-    status_change = newvalues.get('status')
-    status_close = status_change and newvalues['status'] == db.status.lookup('closed')
-
-    # Make sure resolution and superseder get only set when status->close
-    if not status_change or not status_close:
-        if newvalues.get('resolution') or newvalues.get('superseder'):
-            raise ValueError, "resolution and superseder must only be set when a offer is closed"
-
-    # Make sure resolution is set when status->close
-    if status_close:
-        if not newvalues.get('resolution'):
-            raise ValueError, "resolution must be set when a offer is closed"
-
-        # Make sure superseder is set when resolution->duplicate
-        if newvalues['resolution'] == db.resolution.lookup('duplicate'):
-            if not newvalues.get('superseder'):
-                raise ValueError, "please provide a superseder when closing a offer as 'duplicate'"
-
-
-
-def resolve_dependencies(db, cl, nodeid, oldvalues):
-    """ When we resolve an offer that's a blocker, remove it from the
-    blockers list of the offer(s) it blocks."""
-
-    newstatus = cl.get(nodeid,'status')
-
-    # no change?
-    if oldvalues.get('status', None) == newstatus:
-        return
-
-    closed_id = db.status.lookup('closed')
-
-    # interesting?
-    if newstatus != closed_id:
-        return
+        # reject posts attempted by mere users
+        raise ValueError, "You must not set the status to 'posted'."
 
-    # yes - find all the dependend offers, if any, and remove me from
-    # their dependency list
-    offers = cl.find(dependencies=nodeid)
-    for offerid in offers:
-        dependencies = cl.get(offerid, 'dependencies')
-        if nodeid in dependencies:
-            dependencies.remove(nodeid)
-            cl.set(offerid, dependencies=dependencies)
+def inner_generate(db, cl):
+    filename = os.path.join(db.config.HOME,
+                            db.config.options['TEMPLATES'].get(),
+                            "posted.txt")
+    f = open(filename, "w")
+    for offer in cl.filter(None, {'status':posted},
+                                 sort=[('-','posted')]):
+        offer = cl.getnode(offer)
+        head = ""
+        if offer.organization_url:
+            head += "`"
+        head += offer.organization
+        if offer.organization_url:
+            head += "`__"
+        if offer.agency:
+            head += " [AGENCY]"
+        head += " (%s)" % offer.location
+        print >>f, head
+        print >>f, "="*len(head)
+        print >>f
+        print >>f, "*Posted: %s*" % offer.posted.pretty()
+        print >>f
+        if offer.description:
+            print >>f, "**Job Description**:", db.msg.get(offer.description,
+                                                          'content')
+            print >>f
+        if offer.python_used_for:
+            print >>f, "**What Python is used for**:", \
+                  db.msg.get(offer.python_used_for, 'content')
+            print >>f
+        print >>f, '----------'
+        print >>f
+        
+    f.close()
+
+def generate(db, cl, nodeid, oldvalues):
+    if cl.get(nodeid, 'status') == posted:
+        inner_generate(db,cl)
 
 
 def init(db):
+    global posted
+    posted = db.status.lookup('posted')
     # fire before changes are made
     db.offer.audit('create', init_status)
-#    db.offer.audit('create', block_resolution)
-#    db.offer.audit('set', block_resolution)
-#    db.offer.audit('set', resolve)
+    db.offer.audit('set', audit_status)
 
     # adjust after changes are committed
-#    db.offer.react('set', resolve_dependencies)
+    db.offer.react('set', generate)

Modified: tracker/instances/jobs/html/offer.item.html
==============================================================================
--- tracker/instances/jobs/html/offer.item.html	(original)
+++ tracker/instances/jobs/html/offer.item.html	Sat Feb 16 19:05:17 2008
@@ -40,14 +40,13 @@
   <input type="hidden" name="@template" value="item"/>
   <input type="hidden" name="@required" value="title,organization"/>
 <fieldset><legend>Posted content</legend>
-<span tal:replace="structure context/submit">submit button</span>
 <table class="form">
 
 <tr>
  <th class="required" i18n:translate="">Title:</th>
- <td tal:condition="context/is_edit_ok"
+ <td tal:condition="context/title/is_edit_ok"
      tal:content="structure python:context.title.field(size=60)">Title</td>
- <td tal:condition="not:context/is_edit_ok">
+ <td tal:condition="not:context/title/is_edit_ok">
   <span tal:content="structure context/title/plain"/>
   <input type="hidden" name="title" tal:attributes="value context/title">
  </td>
@@ -55,9 +54,9 @@
 
 <tr>
  <th>Company</th>
- <td tal:condition="context/is_edit_ok"
+ <td tal:condition="context/organization/is_edit_ok"
      tal:content="structure python:context.organization.field(size=60)"></td>
- <td tal:condition="not:context/is_edit_ok">
+ <td tal:condition="not:context/organization/is_edit_ok">
   <span tal:content="structure context/organization/plain"/>
   <input type="hidden" name="title" tal:attributes="value context/organization">
  </td>
@@ -65,33 +64,57 @@
 
 <tr>
  <th>Company URL (optional)</th>
- <td tal:condition="context/is_edit_ok"
+ <td tal:condition="context/organization_url/is_edit_ok"
      tal:content="structure python:context.organization_url.field(size=60)">OK</td>
- <td tal:condition="not:context/is_edit_ok">
-  <span tal:content="structure context/organization/plain"/>
+ <td tal:condition="not:context/organization_url/is_edit_ok">
+  <span tal:content="structure context/organization_url/plain"/>
   <input type="hidden" name="title" tal:attributes="value context/organization_url">
  </td>
 </tr>
 
-<tr tal:condition="context/is_edit_ok">
+<tr>
+ <th>We are a job agency</th>
+ <td tal:condition="context/agency/is_edit_ok"
+     tal:content="structure context/agency/field">OK</td>
+ <td tal:condition="not:context/agency/is_edit_ok">
+  <span tal:content="structure context/agency/plain"/>
+  <input type="hidden" name="title" tal:attributes="value context/agency">
+ </td>
+</tr>
+
+<tr>
+ <th>Job Location</th>
+ <td tal:condition="context/location/is_edit_ok"
+     tal:content="structure python:context.location.field(size=60)">OK</td>
+ <td tal:condition="not:context/location/is_edit_ok">
+  <span tal:content="structure context/location/plain"/>
+  <input type="hidden" name="title" tal:attributes="value context/location">
+ </td>
+</tr>
+
+<tr tal:define="curval python:context.description and context.description.content">
  <th><tal:block i18n:translate="">Description</tal:block>:</th>
- <td tal:define="curval python:context.description and context.description.content">
+ <td  tal:condition="context/description/is_edit_ok">
   <input type="hidden" name="@link at description" value="msg-1">
   <textarea tal:content="request/form/msg-1 at content/value | curval"
             name="msg-1 at content" rows="10" cols="72"></textarea>
  </td>
+ <td tal:condition="not:context/description/is_edit_ok" tal:content="curval"/>
 </tr>
 
-<tr tal:condition="context/is_edit_ok">
+<tr tal:define="curval python:context.python_used_for and context.python_used_for.content">
  <th><tal:block i18n:translate="">What Python is used for</tal:block>:</th>
- <td tal:define="curval python:context.python_used_for and context.python_used_for.content">
+ <td tal:condition="context/description/is_edit_ok">
   <input type="hidden" name="@link at python_used_for" value="msg-2">
   <textarea tal:content="request/form/msg-2 at content/value | curval"
             name="msg-2 at content" cols="72"></textarea>
  </td>
+ <td tal:condition="not:context/python_used_for/is_edit_ok"
+     tal:content="curval"/>
 </tr>
-
 </table>
+<span tal:condition="context/title/is_edit_ok"
+      tal:replace="structure context/submit">submit button</span>
 </fieldset>
 </form>
 

Modified: tracker/instances/jobs/html/page.html
==============================================================================
--- tracker/instances/jobs/html/page.html	(original)
+++ tracker/instances/jobs/html/page.html	Sat Feb 16 19:05:17 2008
@@ -201,6 +201,8 @@
 <div id="body-main">
 <div id="content">
 <div id="breadcrumb"><span metal:define-slot="body_title">body title</span></div>
+<h1 style="color:red">This is a demo installation. Do not use it for real jobs.</h1>
+
  <p tal:condition="options/error_message | nothing" class="error-message"
     tal:repeat="m options/error_message" tal:content="structure m" />
  <p tal:condition="options/ok_message | nothing" class="ok-message">

Modified: tracker/instances/jobs/schema.py
==============================================================================
--- tracker/instances/jobs/schema.py	(original)
+++ tracker/instances/jobs/schema.py	Sat Feb 16 19:05:17 2008
@@ -67,10 +67,12 @@
 offer = IssueClass(db, "offer",
                    organization=String(),
                    organization_url=String(),
+                   location=String(),
                    agency=Boolean(),
                    description=Link('msg'),
                    python_used_for=Link('msg'),
                    status=Link('status'),
+                   posted=Date()
                    )
 
 #
@@ -167,12 +169,29 @@
                               description='User can report and discuss offers')
 db.security.addPermissionToRole('User', p)
 
+# Users may edit their offers before they get posted
+def edit_unposted(db, userid, itemid):
+    status = db.offer.get(itemid, 'status')
+    status = db.status.get(status, 'name')
+    if status == 'posted':
+        return False
+    return own_offer(db, userid, itemid)
+
 p = db.security.addPermission(name='Edit', klass='offer',
                               properties=('title','organization',
                                           'organization_url', 'agency',
                                           'description', 'python_used_for',
-                                          'messages', 'files', 'nosy'),
-                              description='User can add and discuss offers')
+                                          'messages', 'files'),
+                              description='User can edit unposted offers',
+                              check=edit_unposted)
+db.security.addPermissionToRole('User', p)
+
+# Users can edit the status always (e.g. to withdraw an issue);
+# an auditor will make sure they don't change it to "posted".
+p = db.security.addPermission(name='Edit', klass='offer',
+                              properties=('status','nosy'),
+                              description='User can change the status of their offers',
+                              check=own_offer)
 db.security.addPermissionToRole('User', p)
 
 db.security.addPermissionToRole('User', 'SB: May Report Misclassified')
@@ -278,7 +297,7 @@
 # Note permissions settings for file and msg above (due to spambayes
 # integration).
 
-for cl in 'offer', 'status':
+for cl in 'status',:
     db.security.addPermissionToRole('Anonymous', 'View', cl)
 
 # Allow users to see the realname


More information about the Python-checkins mailing list