Changeset 4789
- Timestamp:
- 11 Jan 2010, 19:01:31 (15 years ago)
- Location:
- waeup/trunk
- Files:
-
- 12 deleted
- 23 edited
- 110 copied
Legend:
- Unmodified
- Added
- Removed
-
waeup/trunk
-
Property
svn:ignore
set to
develop-eggs
bin
parts
.installed.cfg
-
Property
svn:ignore
set to
-
waeup/trunk/buildout.cfg
r3516 r4789 1 1 [buildout] 2 2 develop = . 3 parts = app data zopectl i18n test 3 parts = app data zopectl i18n test waeupdocs coverage-detect coverage-report 4 4 find-links = http://download.zope.org/distribution/ 5 5 newest = false 6 extends= http://grok.zope.org/releaseinfo/grok- 0.13.cfg6 extends= http://grok.zope.org/releaseinfo/grok-1.0.cfg 7 7 versions = versions 8 9 [versions] 10 zc.sourcefactory = 0.3.5 11 zope.testing = 3.7.0 12 z3c.testsetup = 0.4.0 13 hurry.workflow = 0.10 14 hurry.query = 0.9.2 15 zope.xmlpickle = 3.4.0 16 hurry.yui = 2.7.0 17 hurry.zoperesource = 0.4 18 megrok.layout = 0.9 19 8 20 9 21 [app] … … 29 41 /> 30 42 43 <grant permission="zope.View" 44 principal="zope.Authenticated" /> 45 <grant permission="zope.app.dublincore.view" 46 principal="zope.Authenticated" /> 47 31 48 <!-- Replace the following directive if you don't want 32 49 public access --> … … 35 52 <grant permission="zope.app.dublincore.view" 36 53 principal="zope.Anybody" /> 54 55 <grant permission="waeup.Public" 56 principal="zope.Everybody" /> 37 57 38 58 <role id="zope.Manager" title="Site Manager" /> … … 57 77 defaults = ['--tests-pattern', '^f?tests$', '-v'] 58 78 79 # Collect test coverage data. 80 [coverage-detect] 81 recipe = zc.recipe.testrunner 82 eggs = waeup 83 defaults = ['--tests-pattern', '^f?tests$', '-v', '--coverage', 'coverage'] 84 85 # Create a coverage report. 86 # Make sure to run bin/coverage-detect to collect the data for the report 87 # first! 88 [coverage-report] 89 recipe = zc.recipe.egg 90 eggs = z3c.coverage 91 scripts = coverage 92 arguments = ('${buildout:parts-directory}/coverage-detect/coverage', '${buildout:parts-directory}/coverage-detect/coverage/report') 93 94 95 59 96 # this section named so that the i18n scripts are called bin/i18n... 60 97 [i18n] … … 64 101 location = src/waeup 65 102 output = locales 103 104 [waeupdocs] 105 recipe = z3c.recipe.sphinxdoc 106 eggs = waeup [docs] 107 default.css = 108 layout.html = 109 -
waeup/trunk/setup.py
r3520 r4789 21 21 install_requires=['setuptools', 22 22 'grok', 23 'grokui.admin', 23 24 'hurry.query', 24 25 'hurry.workflow', 25 26 # Add extra requirements here 27 'zope.xmlpickle', 28 'hurry.yui', 29 'hurry.zoperesource', 30 'zc.sourcefactory', 31 'megrok.layout', 26 32 ], 33 extras_require=dict( 34 docs=['Sphinx', 35 'z3c.recipe.sphinxdoc', 36 ], 37 ), 27 38 entry_points=""" 28 39 # Add entry points here -
waeup/trunk/src/waeup/README.txt
r3523 r4789 5 5 6 6 A portal software for student registration. 7 8 Prerequisites 9 ============= 10 11 Before we can work with the environment, we have to register all the 12 utilities, adapters, etc. We grok the `waeup` package to do that:: 13 14 >>> import grok 15 >>> grok.testing.grok('waeup') 7 16 8 17 Universities … … 22 31 23 32 >>> u.name 24 u' Unnamed'33 u'Sample University' 25 34 26 Universities are basically also containers for faculties. 35 Universities are basically also containers for faculties, students and 36 hostels:: 37 38 >>> u['faculties'] 39 <waeup.university.facultycontainer.FacultyContainer object at 0x...> 40 41 >>> u['students'] 42 <waeup.student.studentcontainer.StudentContainer object at 0x...> 43 44 >>> u['hostels'] 45 <waeup.hostel.hostelcontainer.HostelContainer object at 0x...> 46 47 We can export universities. For this we lookup an appropriate exporter 48 first:: 49 50 >>> from waeup.interfaces import IWAeUPExporter 51 >>> exporter = IWAeUPExporter(u) 52 >>> exporter 53 <waeup.utils.importexport.Exporter object at 0x...> 54 55 Now we can trigger the export:: 56 57 >>> exporter.export() 58 <cStringIO.StringO object at 0x...> 59 60 We can also get an XML representation as file. If we do not provide a 61 filepath, we will get an instance of `cStringIO.StringIO`, i.e. a 62 memory file:: 63 64 >>> from waeup.interfaces import IWAeUPXMLExporter 65 >>> exporter = IWAeUPXMLExporter(u) 66 >>> f = exporter.export() 67 >>> f 68 <cStringIO.StringO object at 0x...> 69 70 >>> print f.read() 71 <?xml version="1.0" encoding="utf-8" ?> 72 <pickle> 73 <initialized_object id="..."> 74 ... 75 </pickle> 76 27 77 28 78 Faculties … … 34 84 We can create faculties easily:: 35 85 36 >>> from waeup. appimport Faculty86 >>> from waeup.university.faculty import Faculty 37 87 >>> f = Faculty() 38 88 >>> f 39 <waeup. app.Faculty object at 0x...>89 <waeup.university.faculty.Faculty object at 0x...> 40 90 41 91 Also faculties want to be named:: 42 92 43 >>> f. name93 >>> f.title 44 94 u'Unnamed Faculty' 45 95 -
waeup/trunk/src/waeup/__init__.py
r3521 r4789 1 import grok 2 from waeup.interfaces import IWAeUPObject 3 from zope.annotation.attribute import AttributeAnnotations 4 from zope.annotation.interfaces import IAnnotations 5 6 class WAeUPAttributeAnnotations(AttributeAnnotations, grok.Adapter): 7 """An adapter to IAnnotations for any WAeUPObject. 8 9 Providing this adapter, each WAeUP object becomes (attribute) 10 annotatable. 11 """ 12 grok.provides(IAnnotations) 13 grok.context(IWAeUPObject) -
waeup/trunk/src/waeup/app.py
r3530 r4789 1 1 import grok 2 from grok import index 3 from zope.interface import Interface 4 from interfaces import IUniversity 5 from setup import app_setup 6 from viewlets import MainArea 2 from zope.app.authentication.authentication import PluggableAuthentication 3 from zope.app.security.interfaces import IAuthentication 4 from zope.component import createObject 5 6 from waeup.interfaces import IUniversity, ICSVDataReceivers 7 from waeup.authentication import setup_authentication 8 from waeup.datacenter import DataCenter 9 from waeup.users import UserContainer 7 10 8 11 class University(grok.Application, grok.Container): 9 grok.implements(IUniversity) 10 11 def __init__(self, name=u'Unnamed', **kw): 12 """A university. 13 """ 14 grok.implements(IUniversity, ICSVDataReceivers) 15 # Setup authentication for this app. Note: this is only 16 # initialized, when a new instance of this app is created. 17 grok.local_utility( 18 PluggableAuthentication, provides = IAuthentication, 19 setup = setup_authentication) 20 21 def __init__(self, name=u'Sample University', **kw): 12 22 super(University, self).__init__(**kw) 13 23 self.name = name 14 app_setup.setup(self)24 self.setup() 15 25 16 class Content(grok.Viewlet): 17 grok.viewletmanager(MainArea) 18 grok.context(IUniversity) 19 20 21 class Edit(grok.EditForm): 22 grok.context(University) 23 grok.AutoFields(IUniversity) 26 def setup(self): 27 self['students'] = createObject(u'waeup.StudentContainer') 28 self['hostels'] = createObject(u'waeup.HostelContainer') 29 self['faculties'] = createObject(u'waeup.FacultyContainer') 30 self['users'] = UserContainer() 31 self['datacenter'] = DataCenter() -
waeup/trunk/src/waeup/browser.txt
r3523 r4789 1 The waeup package 2 ******************** 1 Browsing the WAeUP portal 2 ************************* 3 4 Here we visit all parts of a WAeUP portal using a browser. 3 5 4 6 :Test-Layer: functional … … 34 36 >>> browser.open('http://localhost/myuniversity') 35 37 >>> print browser.contents 36 < html>...37 ... <h1>Congratulations!</h1>...38 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 39 ...Welcome to the... 38 40 ... 39 41 40 42 We can also get an edit view of a university:: 41 43 42 >>> browser.open('http://localhost/myuniversity/ edit')43 >>> print browser.contents 44 < html>...45 ...<form action="http://localhost/myuniversity/ edit"44 >>> browser.open('http://localhost/myuniversity/manage') 45 >>> print browser.contents 46 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 47 ...<form action="http://localhost/myuniversity/manage" 46 48 ... 47 49 48 50 The edit form contains the default value for the university name:: 49 51 50 >>> ' Unnamed' in browser.contents52 >>> 'Sample University' in browser.contents 51 53 True 54 55 We can export a university as XML:: 56 57 >>> browser.open('http://localhost/myuniversity/export.xml') 58 >>> print browser.contents 59 <?xml version="1.0" encoding="utf-8" ?> 60 <pickle> 61 ... 62 </pickle> 63 64 >>> print browser.headers 65 Status: 200 Ok 66 Content-Length: ... 67 Content-Type: text/xml; charset=UTF-8 68 X-Powered-By: Zope (www.zope.org), Python (www.python.org) 69 52 70 53 71 Faculties 54 72 ========= 55 73 56 Wie can add faculties, by calling and submitting an add form of an 57 university. The add form can be retrieved by calling the 58 ``addfaculty`` view of an university::59 60 >>> browser.open('http://localhost/myuniversity/ addfaculty')61 >>> print browser.contents 62 < html>...74 Faculties are stored in a special container of `IUniversity` 75 instances. The container is called ``faculties`` and provides an 76 add-form to add new faculties:: 77 78 >>> browser.open('http://localhost/myuniversity/faculties/add') 79 >>> print browser.contents 80 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 63 81 ...<span class="required">*</span><span>Name of Faculty</span> 64 82 ... … … 66 84 We fill in a new name for our new faculty:: 67 85 68 >>> ctrl = browser.getControl(name='form. name')86 >>> ctrl = browser.getControl(name='form.title') 69 87 >>> ctrl.value = 'TestFac' 70 88 89 Furthermore we add a prefix and a code (kind of abbreviation): 90 91 >>> browser.getControl(name='form.code').value = 'TF' 92 71 93 Finally we click on 'Add Faculty' to add the new thing:: 72 94 73 >>> browser.getControl('Add Faculty').click() 74 >>> #print browser.contents 95 >>> browser.getControl('Add faculty').click() 75 96 76 97 We can view a faculty by browsing a URL like this:: 77 98 78 >>> browser.open('http://localhost/myuniversity/ TestFac')99 >>> browser.open('http://localhost/myuniversity/faculties/TF') 79 100 80 101 Afterwards, the faculty should be visible: 81 102 82 >>> browser.open('http://localhost/myuniversity/') 83 >>> print browser.contents 84 <html... 85 ...<h2>Your faculties:</h2> 86 ...<a href="http://localhost/myuniversity/TestFac">TestFac</a> 87 ... 88 89 90 103 >>> browser.open('http://localhost/myuniversity/faculties') 104 >>> print browser.contents 105 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 106 ...<h2>Registered Faculties</h2> 107 ...<td><a href="http://localhost/myuniversity/faculties/TF">TF</a></td><td>Faculty of TestFac</td> 108 ... 109 110 We can 'visit' each faculty by clicking on the appropriate link: 111 112 >>> browser.getLink('TF').click() 113 >>> print browser.contents 114 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 115 ...<h2>Faculty of TestFac (TF)</h2>... 116 ... 117 118 Modifying faculties 119 ------------------- 120 121 A faculty can directly be reached by its code: 122 123 >>> browser.open('http://localhost/myuniversity/faculties/TF') 124 125 We can change the settings for a faculty by clicking on the 126 provided 'Edit settings' button: 127 128 >>> browser.getLink('Edit settings').click() 129 130 Let's set a new title and save the form: 131 132 >>> browser.getControl(name='form.title').value = "My test faculty" 133 >>> browser.getControl(name='form.actions.save').click() 134 135 Clicking 'Save' we will stay on the settings form. So we can change 136 the department again. This time we will return to the overview page 137 afterwards: 138 139 >>> browser.getControl(name='form.title').value = "My renamed faculty" 140 >>> ctrl = browser.getControl("Save and return") 141 >>> ctrl.click() 142 143 If we go to the settings page and click ``Cancel`` nothing will be 144 changed: 145 146 >>> browser.getLink('Edit settings').click() 147 >>> browser.getControl(name='form.title').value = "Blah" 148 >>> browser.getControl('Cancel').click() 149 150 Our faculty was indeed renamed to ``My renamed faculty`` and not to 151 ``Blah``: 152 153 >>> browser.open('http://localhost/myuniversity/faculties') 154 >>> print browser.contents 155 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 156 ...<h2>Registered Faculties</h2> 157 ...<td><a href="http://localhost/myuniversity/faculties/TF">TF</a></td><td>Faculty of My renamed faculty</td> 158 ... 159 160 161 Departments 162 =========== 163 164 Adding departments 165 ------------------ 166 167 Departments are stored in :class:`IFaculty` instances with their code 168 as key. Faculties therefore are also department containers. Faculties 169 provides an add-form to add new departments: 170 171 >>> browser.open('http://localhost/myuniversity/faculties/TF/add') 172 >>> print browser.contents 173 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 174 ...<span class="required">*</span><span>Name of Department</span> 175 ... 176 177 We fill in a new name for our new department: 178 179 >>> ctrl = browser.getControl(name='form.title') 180 >>> ctrl.value = 'TestDept' 181 182 Furthermore we add a code (kind of abbreviation): 183 184 >>> browser.getControl(name='form.code').value = 'TD' 185 186 Finally we click on 'Add Department' to add the new thing:: 187 188 >>> browser.getControl('Add department').click() 189 190 If we try to register a department under the same code twice we will 191 get an error: 192 193 >>> browser.open('http://localhost/myuniversity/faculties/TF/add') 194 >>> ctrl = browser.getControl(name='form.title') 195 >>> ctrl.value = 'Another TestDept with same code' 196 >>> browser.getControl(name='form.code').value = 'TD' 197 >>> browser.getControl('Add department').click() 198 >>> print browser.contents 199 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 200 ...<div>The name chosen already exists in the database</div> 201 ... 202 203 We can view a department by browsing a URL like this: 204 205 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 206 207 Afterwards, the department should be visible: 208 209 >>> browser.open('http://localhost/myuniversity/faculties/TF') 210 >>> print browser.contents 211 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 212 ...<h2>Registered Departments:</h2> 213 ...<td><a href="http://localhost/myuniversity/faculties/TF/TD">TD</a></td><td>Department of TestDept</td> 214 ... 215 216 217 Modifying departments 218 --------------------- 219 220 We can change the settings for a department by clicking on the 221 provided 'Edit settings' button: 222 223 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 224 >>> browser.getLink('Edit settings').click() 225 226 Let's set a new title and save the form: 227 228 >>> browser.getControl(name='form.title').value = "My test dept" 229 >>> browser.getControl(name='form.actions.save').click() 230 231 Clicking 'Save' we will stay on the settings form. So we can change 232 the department again. This time we will return to the overview page 233 afterwards: 234 235 >>> browser.getControl(name='form.title').value = "My renamed dept" 236 >>> ctrl = browser.getControl("Save and return") 237 >>> ctrl.click() 238 239 If we go to the settings page and click ``Cancel`` nothing will be 240 changed: 241 242 >>> browser.getLink('Edit settings').click() 243 >>> browser.getControl(name='form.title').value = "Blah" 244 >>> browser.getControl('Cancel').click() 245 246 Our department was indeed renamed to ``My renamed dept`` and not to 247 ``Blah``: 248 249 >>> browser.open('http://localhost/myuniversity/faculties/TF') 250 >>> print browser.contents 251 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 252 ...<h2>Registered Departments:</h2> 253 ...<td><a href="http://localhost/myuniversity/faculties/TF/TD">TD</a></td><td>Department of My renamed dept</td> 254 ... 255 256 257 Courses 258 ======= 259 260 Once we have a department, we can add courses. 261 262 Adding courses 263 -------------- 264 265 Courses are stored in :class:`ICourseContainer` instances with their 266 code as key. CourseContainers are normally availabe as `course` 267 attribute of :class:`waeup.university.department.Department` 268 instances. 269 270 To ease the life of users we do not require to browse the 271 coursecontainers (which have a rather flat user interface), but 272 provide adding of courses in department views. 273 274 Each department provides a ``Add course`` action button near top. 275 276 Departments provide an add-form to add new courses: 277 278 >>> dept_url = 'http://localhost/myuniversity/faculties/TF/TD' 279 >>> browser.open(dept_url + '/addcourse') 280 >>> print browser.contents 281 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 282 ...<span class="required">*</span><span>Title of course</span> 283 ... 284 285 We fill in a name for our new course: 286 287 >>> ctrl = browser.getControl(name='form.title') 288 >>> ctrl.value = 'My Course 1' 289 290 Furthermore we add a code (kind of abbreviation): 291 292 >>> browser.getControl(name='form.code').value = 'COURSE1' 293 294 This course will take place in the the first semester, so we set the 295 `semester` value to 1: 296 297 >>> ctrl = browser.getControl(name='form.semester') 298 >>> ctrl.options 299 ['0', '1', '2', '3'] 300 301 >>> ctrl.displayOptions 302 ['N/A', 'First Semester', 'Second Semester', 'Combined'] 303 304 >>> ctrl.value = ['1'] 305 306 Finally, we create the course: 307 308 >>> browser.getControl('Add course').click() 309 310 If we try to register a course under the same code twice we will 311 get an error: 312 313 >>> browser.open(dept_url + '/addcourse') 314 >>> ctrl = browser.getControl(name='form.title') 315 >>> ctrl.value = 'Another course with same code' 316 >>> browser.getControl(name='form.code').value = 'COURSE1' 317 >>> browser.getControl('Add course').click() 318 >>> print browser.contents 319 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 320 ...<div>The code chosen already exists in the database</div> 321 ... 322 323 Our course will be linked under the code on the department page: 324 325 >>> browser.open(dept_url) 326 >>> browser.getLink('COURSE1').click() 327 >>> browser.url 328 'http://localhost/myuniversity/faculties/TF/TD/courses/COURSE1' 329 330 Before we really add a course we can cancel the action and will be 331 redirected to the department page: 332 333 >>> browser.open(dept_url + '/addcourse') 334 >>> browser.getControl('Cancel').click() 335 >>> browser.url 336 'http://localhost/myuniversity/faculties/TF/TD' 337 338 339 Modifying courses 340 ----------------- 341 342 We can change the settings for a course by clicking on the provided 343 'Edit settings' link: 344 345 >>> browser.open(dept_url + '/courses/COURSE1') 346 >>> browser.getLink('Edit settings').click() 347 348 When modifying a course, we cannot change the code any more: 349 350 >>> browser.getControl(name='form.code') 351 Traceback (most recent call last): 352 ... 353 LookupError: name 'form.code' 354 355 Let's set a new title and save the form: 356 357 >>> browser.getControl(name='form.title').value = "My test course" 358 >>> browser.getControl(name='form.actions.save').click() 359 360 Clicking 'Save' we will stay on the settings form. So we can change 361 the course again. This time we will return to the overview page 362 afterwards: 363 364 >>> browser.getControl(name='form.title').value = "My renamed course" 365 >>> ctrl = browser.getControl("Save and return") 366 >>> ctrl.click() 367 368 If we go to the settings page and click ``Cancel`` nothing will be 369 changed: 370 371 >>> browser.getLink('Edit settings').click() 372 >>> browser.getControl(name='form.title').value = "Blah" 373 >>> browser.getControl('Cancel').click() 374 375 Our course was indeed renamed to ``My renamed course`` and not to 376 ``Blah``: 377 378 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 379 >>> print browser.contents 380 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 381 ...<div name="thecoursetable"> 382 ...<td>My renamed course</td>... 383 ... 384 385 386 Deleting courses 387 ---------------- 388 389 We can delete courses by browsing the containing department and 390 clicking on the appropriate 'Delete' button. As we have only one 391 course, there is only one 'Delete' button yet: 392 393 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 394 >>> 'My renamed course' in browser.contents 395 True 396 397 >>> browser.getControl('Delete').click() 398 399 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 400 >>> 'My renamed course' in browser.contents 401 False 402 403 404 Certificates 405 ============ 406 407 Once we have a department, we can add also certificats. 408 409 Adding certificates 410 ------------------- 411 412 Certificates are stored in :class:`ICertificateContainer` instances 413 with their code as key. CertificateContainers are normally availabe as 414 `certificates` attribute of 415 :class:`waeup.university.department.Department` instances. 416 417 To ease the life of users we do not require to browse the 418 certificatecontainers (which have in fact no user interface), but 419 provide adding of certificates in department views. 420 421 Each department provides a ``Add certificate`` action button near top. 422 423 Departments provide an add-form to add new certificates: 424 425 >>> dept_url = 'http://localhost/myuniversity/faculties/TF/TD' 426 >>> browser.open(dept_url + '/addcertificate') 427 >>> print browser.contents 428 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 429 ...<span class="required">*</span><span>title</span> 430 ... 431 432 We fill in a name for our new cert: 433 434 >>> ctrl = browser.getControl(name='form.title') 435 >>> ctrl.value = 'My Certificate 1' 436 437 Furthermore we add a code (kind of abbreviation): 438 439 >>> browser.getControl(name='form.code').value = 'CERT1' 440 441 Set the remaining required fields: 442 443 >>> browser.getControl(name='form.category').value = 'UME' 444 >>> browser.getControl(name='form.study_mode').value = 'combined' 445 >>> browser.getControl(name='form.start_level').value = '100' 446 >>> browser.getControl(name='form.end_level').value = '400' 447 >>> browser.getControl(name='form.application_category').value = 'UME' 448 >>> browser.getControl(name='form.m_prefix').value = 'something' 449 >>> browser.getControl(name='form.max_pass').value = '400' 450 451 Finally, we create the certificate: 452 453 >>> browser.getControl('Add certificate').click() 454 455 If we try to register a certificate under the same code twice we will 456 get an error: 457 458 >>> browser.open(dept_url + '/addcertificate') 459 >>> ctrl = browser.getControl(name='form.title') 460 >>> ctrl.value = 'Another cert with same code' 461 >>> browser.getControl(name='form.code').value = 'CERT1' 462 >>> browser.getControl(name='form.category').value = 'UME' 463 >>> browser.getControl(name='form.study_mode').value = 'combined' 464 >>> browser.getControl(name='form.start_level').value = '100' 465 >>> browser.getControl(name='form.end_level').value = '400' 466 >>> browser.getControl(name='form.application_category').value = 'UME' 467 >>> browser.getControl(name='form.m_prefix').value = 'something' 468 >>> browser.getControl(name='form.max_pass').value = '400' 469 470 >>> browser.getControl('Add certificate').click() 471 >>> print browser.contents 472 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 473 ...<div>The name chosen already exists in the database</div> 474 ... 475 476 Our certificate will be linked under the code on the department page: 477 478 >>> browser.open(dept_url) 479 >>> browser.getLink('CERT1').click() 480 >>> browser.url 481 'http://localhost/myuniversity/faculties/TF/TD/certificates/CERT1' 482 483 Before we really add a certificate we can cancel the action and will be 484 redirected to the department page: 485 486 >>> browser.open(dept_url + '/addcertificate') 487 >>> browser.getControl('Cancel').click() 488 >>> browser.url 489 'http://localhost/myuniversity/faculties/TF/TD' 490 491 492 Modifying certificates 493 ---------------------- 494 495 We can change the settings for a cert by clicking on the provided 496 'Edit settings' link: 497 498 >>> browser.open(dept_url + '/certificates/CERT1') 499 >>> browser.getLink('Edit settings').click() 500 501 When modifying a certificate, we cannot change the code any more: 502 503 >>> browser.getControl(name='form.code') 504 Traceback (most recent call last): 505 ... 506 LookupError: name 'form.code' 507 508 Let's set a new title and save the form: 509 510 >>> browser.getControl(name='form.title').value = "My test cert" 511 >>> browser.getControl(name='form.actions.save').click() 512 513 Clicking 'Save' we will stay on the settings form. So we can change 514 the cert again. This time we will return to the overview page 515 afterwards: 516 517 >>> browser.getControl(name='form.title').value = "My renamed cert" 518 >>> ctrl = browser.getControl("Save and return") 519 >>> ctrl.click() 520 521 If we go to the settings page and click ``Cancel`` nothing will be 522 changed: 523 524 >>> browser.getLink('Edit settings').click() 525 >>> browser.getControl(name='form.title').value = "Blah" 526 >>> browser.getControl('Cancel').click() 527 528 Our certificate was indeed renamed to ``My renamed cert`` and not to 529 ``Blah``: 530 531 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 532 >>> print browser.contents 533 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 534 ...<div name="thecerttable"> 535 ...<td>My renamed cert</td>... 536 ... 537 538 539 Deleting certificates 540 --------------------- 541 542 We can delete certificates by browsing the containing department and 543 clicking on the appropriate 'Delete' button. As we have only one 544 certificate, there is only one 'Delete' button yet: 545 546 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 547 >>> 'My renamed cert' in browser.contents 548 True 549 550 >>> browser.getControl('Delete').click() 551 552 >>> browser.open('http://localhost/myuniversity/faculties/TF/TD') 553 >>> 'My renamed cert' in browser.contents 554 False 555 556 557 CertificateCourses 558 ================== 559 560 Once we have a certificate, we can add also certificate courses. These 561 are references to courses with some extra data. 562 563 Before we can work with certificate courses, we need some certificates 564 and courses to be available. 565 566 >>> browser.open(dept_url + '/addcourse') 567 >>> ctrl = browser.getControl(name='form.title') 568 >>> ctrl.value = 'Another course with same code' 569 >>> browser.getControl(name='form.code').value = 'COURSE1' 570 >>> browser.getControl(name='form.title').value = 'Course 1' 571 >>> browser.getControl('Add course').click() 572 573 >>> browser.open(dept_url + '/addcourse') 574 >>> ctrl = browser.getControl(name='form.title') 575 >>> ctrl.value = 'Another course with same code' 576 >>> browser.getControl(name='form.code').value = 'COURSE2' 577 >>> browser.getControl(name='form.title').value = 'Course 2' 578 >>> browser.getControl('Add course').click() 579 580 >>> browser.open(dept_url + '/addcertificate') 581 >>> ctrl = browser.getControl(name='form.title') 582 >>> ctrl.value = 'Another cert with same code' 583 >>> browser.getControl(name='form.code').value = 'CERT1' 584 >>> browser.getControl(name='form.title').value = 'Certificate 1' 585 >>> browser.getControl(name='form.category').value = 'UME' 586 >>> browser.getControl(name='form.study_mode').value = 'combined' 587 >>> browser.getControl(name='form.start_level').value = '100' 588 >>> browser.getControl(name='form.end_level').value = '400' 589 >>> browser.getControl(name='form.application_category').value = 'UME' 590 >>> browser.getControl(name='form.m_prefix').value = 'something' 591 >>> browser.getControl(name='form.max_pass').value = '400' 592 >>> browser.getControl('Add certificate').click() 593 594 >>> browser.open(dept_url + '/addcertificate') 595 >>> ctrl = browser.getControl(name='form.title') 596 >>> ctrl.value = 'Another cert with same code' 597 >>> browser.getControl(name='form.code').value = 'CERT2' 598 >>> browser.getControl(name='form.title').value = 'Certificate 2' 599 >>> browser.getControl(name='form.category').value = 'UME' 600 >>> browser.getControl(name='form.study_mode').value = 'combined' 601 >>> browser.getControl(name='form.start_level').value = '100' 602 >>> browser.getControl(name='form.end_level').value = '400' 603 >>> browser.getControl(name='form.application_category').value = 'UME' 604 >>> browser.getControl(name='form.m_prefix').value = 'something' 605 >>> browser.getControl(name='form.max_pass').value = '400' 606 >>> browser.getControl('Add certificate').click() 607 608 609 Adding certificatecourses 610 ------------------------- 611 612 Certcourses are stored in :class:`ICertificate` instances 613 with their code as key. 614 615 Each certificate provides a ``Add course`` action button near top. 616 617 Certificates provide an add-form to add new certcourses: 618 619 >>> cert_url = dept_url + '/certificates/CERT1' 620 >>> browser.open(cert_url + '/addcertificatecourse') 621 >>> print browser.contents 622 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 623 ...<span class="required">*</span><span>Level of this course</span> 624 ... 625 626 In the add-form we will get a list of available courses to select 627 from. This list will contain all courses stored in the site, not only 628 the ones from local department: 629 630 >>> ctrl = browser.getControl(name='form.course') 631 >>> ctrl.displayOptions 632 ['COURSE1 Course 1', 'COURSE2 Course 2'] 633 634 If we do not select anything else, the first item will be 635 selected. That's okay for us. Finally, we create the 636 certificatecourse: 637 638 >>> browser.getControl('Add course').click() 639 640 Our certificatecourse will be linked on the parent certificate page: 641 642 >>> browser.open(cert_url) 643 >>> browser.getLink('COURSE1').click() 644 >>> browser.url 645 'http://localhost/my...sity/faculties/TF/TD/certificates/CERT1/COURSE1_100' 646 647 When we started to add a new certificatecourse, we can also cancel the 648 process before submitting. This will bring us back to the certificate 649 page: 650 651 >>> browser.open(cert_url + '/addcertificatecourse') 652 >>> browser.getControl('Cancel').click() 653 >>> browser.url 654 'http://localhost/myuniversity/faculties/TF/TD/certificates/CERT1' 655 656 657 Modifying certificatecourses 658 ---------------------------- 659 660 We can change the settings for a certcourse by clicking on the 661 provided 'Edit settings' link: 662 663 >>> browser.open(cert_url + '/COURSE1_100') 664 >>> browser.getLink('Edit settings').click() 665 666 Let's set a new level (it was 100 before) and save the form. This will 667 bring us to the certificate index page afterwards: 668 669 >>> browser.getControl(name='form.level').value = "200" 670 >>> ctrl = browser.getControl("Save and return") 671 >>> ctrl.click() 672 673 As we changed the level, also the URL will change: 674 675 >>> browser.getLink('COURSE1').click() 676 >>> browser.url 677 'http://localhost/myun.../TF/TD/certificates/CERT1/COURSE1_200' 678 679 If we go to the settings page and click ``Cancel`` nothing will be 680 changed: 681 682 >>> browser.getLink('Edit settings').click() 683 >>> browser.getControl(name='form.level').value = "666" 684 >>> browser.getControl('Cancel').click() 685 686 Our certcourse provides a new level of 200 and not 666: 687 688 >>> browser.open(cert_url + '/COURSE1_200') 689 >>> print browser.contents 690 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 691 ...Level of this course 692 ...200... 693 ... 694 695 696 Deleting certificatecourses 697 --------------------------- 698 699 We can delete certcourses by browsing the containing certificate and 700 clicking on the appropriate 'Delete' button. As we have only one 701 certcourse, there is only one 'Delete' button yet: 702 703 >>> browser.open(cert_url) 704 >>> 'COURSE1_200' in browser.contents 705 True 706 707 >>> browser.getControl('delete').click() 708 709 >>> browser.open(cert_url) 710 >>> 'COURSE1_200' in browser.contents 711 False 712 713 714 Data Center 715 =========== 716 717 The data center helps us uploading files for later import or similar. 718 719 >>> browser.open('http://localhost/myuniversity') 720 >>> browser.getLink('Data Center').click() 721 722 Setting the file path 723 --------------------- 724 725 A datacenter stores files in a path in filesystem. By default this is 726 a directory in the sources: 727 728 >>> print browser.contents 729 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 730 ... 731 <b>Storage path:</b> <span>/.../waeup/files</span> 732 ... 733 734 Going to 'Settings` we can change the path: 735 736 >>> browser.getLink('Edit settings').click() 737 >>> pathsetting = browser.getControl(name='newpath') 738 739 We create a directory and set it as our upload path: 740 741 >>> import os 742 >>> cwd = os.getcwd() 743 >>> uploadpath = os.path.join(cwd, 'testfiles') 744 >>> os.mkdir(uploadpath) 745 >>> pathsetting.value = uploadpath 746 747 And submit the form: 748 749 >>> browser.getControl(name='save').click() 750 751 We clean up the set directory path, as there might be some files be 752 copied some files from installation: 753 754 >>> files = os.listdir(uploadpath) 755 >>> for filename in files: 756 ... os.unlink(os.path.join(uploadpath, filename)) 757 758 The new upload directory is now empty: 759 760 >>> os.listdir(uploadpath) 761 [] 762 763 764 Uploading files 765 --------------- 766 767 Now we can upload files. Most interesting files might be CSV files, 768 that can be imported lateron. We create a CSV file containing faculty 769 descriptions: 770 771 >>> open('faculties.csv', 'wb').write( 772 ... """code,title,title_prefix 773 ... FA,Arts,Faculty 774 ... FS,Sciences,Faculty 775 ... """) 776 777 Now we can upload this file. To do this, we first go to the upload 778 page: 779 780 >>> browser.getLink('Upload data').click() 781 782 and enter the appropriate data in the form: 783 784 >>> filewidget = browser.getControl(name='uploadfile:file') 785 >>> filewidget 786 <Control name='uploadfile:file' type='file'> 787 788 A sidenote for developers: by marking the filewidget with the 789 ``:file`` extension, we tell Zope to handle this field as a file 790 widget. 791 792 >>> import cStringIO 793 >>> filecontents = cStringIO.StringIO( 794 ... open('faculties.csv', 'rb').read()) 795 >>> filewidget.add_file(filecontents, 'text/plain', 'myfaculties.csv') 796 797 >>> browser.getControl(name='SUBMIT').click() 798 799 The file was indeed uploaded: 800 801 >>> os.listdir(uploadpath) 802 ['myfaculties.csv'] 803 804 We create and upload also a CSV file containing departments: 805 806 >>> open('departments.csv', 'wb').write( 807 ... """code,title,title_prefix,faculty_code 808 ... LIT,Literature,Department,FA 809 ... SOC,Sociology,Department,FA 810 ... PHY,Physics,Department,FS 811 ... INF,Informatics,Department,FS 812 ... MAT,Math,Department,FS 813 ... """) 814 815 >>> browser.open('http://localhost/myuniversity/datacenter/upload') 816 >>> browser.getControl(name='uploadfile:file').add_file( 817 ... cStringIO.StringIO(open('departments.csv', 'rb').read()), 818 ... 'text/plain', 'mydepartments.csv') 819 >>> browser.getControl(name='SUBMIT').click() 820 821 We create and upload also a CSV file containing courses: 822 823 >>> open('courses.csv', 'wb').write( 824 ... """code,level,title,passmark,credits,semester,faculty,department 825 ... LI1,,Introduction to Literature I,40,2,1,FA,LIT 826 ... LI2,,Introduction to Literature II,40,2,2,FA,LIT 827 ... AN1,000,Analysis I,40,2,1,FS,MAT 828 ... AN2,000,Analysis II,40,2,2,FS,MAT 829 ... """) 830 831 >>> browser.open('http://localhost/myuniversity/datacenter/upload') 832 >>> browser.getControl(name='uploadfile:file').add_file( 833 ... cStringIO.StringIO(open('courses.csv', 'rb').read()), 834 ... 'text/plain', 'mycourses.csv') 835 >>> browser.getControl(name='SUBMIT').click() 836 837 We create and upload also a CSV file containing certificates: 838 839 >>> open('certificates.csv', 'wb').write( 840 ... """code,title,faculty_code,department_code,category,study_mode,end_level,m_prefix,max_pass,start_level,application_category,review_state 841 ... LBA,BACHELOR OF LITERATURE,FA,LIT,UG,ug_ft,500,LIT,30,100,basic,checked 842 ... LMA,MASTER OF LITERATURE,FA,LIT,UG,ug_pt,500,LIT,30,100,cest,checked 843 ... DME,DIPLOMA OF MATH,FS,MAT,DP,dp_ft,200,DME,30,100,cest,unchecked 844 ... """) 845 846 >>> browser.open('http://localhost/myuniversity/datacenter/upload') 847 >>> browser.getControl(name='uploadfile:file').add_file( 848 ... cStringIO.StringIO(open('certificates.csv', 'rb').read()), 849 ... 'text/plain', 'mycertificates.csv') 850 >>> browser.getControl(name='SUBMIT').click() 851 852 We create and upload also a CSV file containing certificate courses: 853 854 >>> open('certcourses.csv', 'wb').write( 855 ... """code,faculty_code,department_code,certificate_code,level,core_or_elective 856 ... LI1,FA,LIT,LBA,100,True 857 ... LI2,FA,LIT,LBA,200,True 858 ... """) 859 860 >>> browser.open('http://localhost/myuniversity/datacenter/upload') 861 >>> browser.getControl(name='uploadfile:file').add_file( 862 ... cStringIO.StringIO(open('certcourses.csv', 'rb').read()), 863 ... 'text/plain', 'mycertcourses.csv') 864 >>> browser.getControl(name='SUBMIT').click() 865 866 867 Importing a CSV file 868 -------------------- 869 870 As the uploaded file conforms with what we expect from a faculty-CSV 871 file, we can import it. To do this we click the ``Import CSV data`` 872 link: 873 874 >>> browser.open('http://localhost/myuniversity/datacenter') 875 >>> browser.getLink('Import CSV data').click() 876 877 Here we get all importable files listed: 878 879 >>> print browser.contents 880 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 881 ...The following files are available for import:... 882 ...mycertcourses.csv...Certificate Course Importer... 883 ...mycertificates.csv...Certificate Importer... 884 ...mycourses.csv...Course Importer... 885 ...mydepartments.csv...Department Importer... 886 ...myfaculties.csv...Faculty Importer... 887 ... 888 889 As we can see, the files are analyzed on-the-fly so the system can 890 tell us what kind of importer is available for each. 891 892 We do import the faculty file by clicking on ``Import!`` next to the 893 appropriate file: 894 895 >>> facimport = browser.getControl('Import!', index=4) 896 >>> facimport.click() 897 898 >>> print browser.contents 899 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 900 ...Successfully imported: myfaculties.csv... 901 ... 902 903 We just created two new faculties: 904 905 >>> browser.open('http://localhost/myuniversity/faculties/') 906 >>> print browser.contents 907 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 908 ...<h2>Registered Faculties</h2>... 909 ...Arts... 910 ...Sciences... 911 ... 912 913 We can also import the department data: 914 915 >>> browser.open('http://localhost/myuniversity/datacenter') 916 >>> browser.getLink('Import CSV data').click() 917 >>> browser.getControl('Import!', index=3).click() 918 919 >>> print browser.contents 920 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 921 ...Successfully imported: mydepartments.csv... 922 ... 923 924 We can also import the course data: 925 926 >>> browser.open('http://localhost/myuniversity/datacenter') 927 >>> browser.getLink('Import CSV data').click() 928 >>> browser.getControl('Import!', index=2).click() 929 930 >>> print browser.contents 931 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 932 ...Successfully imported: mycourses.csv... 933 ... 934 935 We can also import the certificate data: 936 937 >>> browser.open('http://localhost/myuniversity/datacenter') 938 >>> browser.getLink('Import CSV data').click() 939 >>> browser.getControl('Import!', index=1).click() 940 941 >>> print browser.contents 942 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 943 ...Successfully imported: mycertificates.csv... 944 ... 945 946 We can also import certificate courses: 947 948 >>> browser.open('http://localhost/myuniversity/datacenter') 949 >>> browser.getLink('Import CSV data').click() 950 >>> browser.getControl('Import!', index=0).click() 951 952 >>> print browser.contents 953 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... 954 ...Successfully imported: mycertcourses.csv... 955 ... 956 957 Clean up: 958 959 >>> import os 960 >>> import shutil 961 >>> shutil.rmtree(uploadpath) -
waeup/trunk/src/waeup/catalog.py
r3527 r4789 1 import sys2 import csv3 import random4 from datetime import datetime5 1 import os 6 2 import grok … … 8 4 from hurry.query.query import Query, Text 9 5 from hurry.query import Eq 10 from app import University 11 from students.interfaces import IStudent 12 from students.student import Student 6 from waeup.app import University 7 from waeup.interfaces import ICourse, ICertificateCourse 8 from waeup.student.interfaces import IStudent 9 from zope.app.catalog.interfaces import ICatalog 10 from zope.app.intid.interfaces import IIntIds 11 from zope.component import getUtility 12 from zope.component.interfaces import ComponentLookupError 13 13 14 14 15 class StudentIndexes(grok.Indexes): … … 20 21 21 22 22 class StudentSearch(grok.View): 23 grok.context(University) 23 class CourseIndexes(grok.Indexes): 24 grok.site(University) 25 grok.name('courses_catalog') 26 grok.context(ICourse) 24 27 25 def update(self, query=None): 26 self.search_result = [] 27 if query is not None: 28 self.search_result = self.search_context(query) 29 print "RESULT: ", list(self.search_result) 28 code = index.Field(attribute='code') 29 title = index.Text(attribute='title') 30 30 31 def search_context(self, query): 32 result = Query().searchResults( 33 Eq(('students_catalog', 'name'), query) 34 ) 35 return result 36 31 class CourseCertificatesIndexes(grok.Indexes): 32 grok.site(University) 33 grok.name('certcourses_catalog') 34 grok.context(ICertificateCourse) 35 36 course_code = index.Field(attribute='getCourseCode') 37 38 @grok.subscribe(ICourse, grok.IObjectAddedEvent) 39 def handleCourseAdd(obj, event): 40 """Index an added course with the local catalog. 41 42 Courses are not indexed automatically, as they are not a 43 dictionary subitem of the accompanied site object 44 (`IUniversity`). I.e. one cannot get them by asking for 45 ``app['FACCODE']['DEPTCODE']['COURSECODE']`` but one has to ask for 46 ``app.faculties['FACCODE']['DEPTCODE'].courses['COURSECODE']``. 47 48 Once, a course is indexed we can leave the further handling to 49 the default component architechture. At least removals will 50 be handled correctly then (and the course unindexed). 51 """ 52 try: 53 cat = getUtility(ICatalog, name='courses_catalog') 54 except ComponentLookupError: 55 # catalog not available. This might happen during tests. 56 return 57 intids = getUtility(IIntIds) 58 index = cat['code'] 59 index.index_doc(intids.getId(obj), obj) 60 61 from zope.interface import Interface 62 from zope import schema 63 64 class IQueryResultItem(Interface): 65 url = schema.TextLine( 66 title = u'URL that links to the found item') 67 title = schema.TextLine( 68 title = u'Title displayed in search results.') 69 description = schema.Text( 70 title = u'Longer description of the item found.') 71 72 73 class QueryResultItem(object): 74 grok.implements(IQueryResultItem) 75 url = None 76 title = None 77 description = None 78 79 def __init__(self, context, view): 80 self.context = context 81 self.url = view.url(context) 82 self.title = context.title 83 self.description = '' 84 85 class CourseQueryResultItem(QueryResultItem): 86 def __init__(self, context, view): 87 self.context = context 88 self.url = view.url(context) 89 self.title = "COURSE: " + context.title 90 self.description = 'code: %s' % context.code 91 92 def search(query=None, view=None): 93 if not query: 94 return [] 95 cat = getUtility(ICatalog, name='courses_catalog') 96 results = list(cat.searchResults(code=(query, query))) 97 98 hitlist = [] 99 results = Query().searchResults( 100 Eq(('courses_catalog', 'code'), query)) 101 for result in results: 102 hitlist.append(CourseQueryResultItem(result, view=view)) 103 104 results = Query().searchResults( 105 Text(('courses_catalog', 'title'), query)) 106 107 for result in results: 108 hitlist.append(CourseQueryResultItem(result, view=view)) 109 110 return hitlist 111 112 def search_context(query): 113 result = Query().searchResults( 114 Eq(('students_catalog', 'name'), query) 115 ) 116 return result -
waeup/trunk/src/waeup/ftesting.zcml
r3523 r4789 10 10 <!-- Typical functional testing security setup --> 11 11 <securityPolicy 12 component="zope. app.securitypolicy.zopepolicy.ZopeSecurityPolicy"12 component="zope.securitypolicy.zopepolicy.ZopeSecurityPolicy" 13 13 /> 14 14 … … 17 17 title="Unauthenticated User" 18 18 /> 19 <unauthenticatedGroup id="zope.Anybody" 20 title="Unauthenticated Users" /> 21 <authenticatedGroup id="zope.Authenticated" 22 title="Authenticated Users" /> 23 <everybodyGroup id="zope.Everybody" 24 title="All Users" /> 25 19 26 <grant 20 27 permission="zope.View" 21 principal="zope.anybody" 28 principal="zope.Anybody" 29 /> 30 <grant 31 permission="zope.app.dublincore.view" 32 principal="zope.Anybody" /> 33 <grant 34 permission="zope.View" 35 principal="zope.Authenticated" 36 /> 37 <grant 38 permission="zope.app.dublincore.view" 39 principal="zope.Authenticated" 40 /> 41 <grant 42 permission="waeup.Public" 43 principal="zope.Everybody" 22 44 /> 23 45 -
waeup/trunk/src/waeup/hostel/hostel.py
r3531 r4789 1 1 import grok 2 from waeup.baseitem import BaseItem 3 from interfaces import IHostel 2 from waeup.interfaces import IHostel 4 3 5 6 class Hostel(BaseItem): 4 class Hostel(grok.Container): 7 5 """This is a hostel record. 8 6 """ … … 12 10 super(Hostel, self).__init__(**kw) 13 11 self.name = name 12 13 grok.global_utility(Hostel, provides=IHostel) -
waeup/trunk/src/waeup/hostel/hostelcontainer.py
r3527 r4789 1 from waeup.basecontainer import BaseContainer 2 from hostel import Hostel 1 import grok 2 from zope.component.interfaces import IFactory 3 from zope.interface import implementedBy 4 from waeup.interfaces import IHostelContainer, IHostel 3 5 4 class HostelContainer(BaseContainer): 5 name = u"Hostels" 6 childClass = Hostel 6 class HostelContainer(grok.Container): 7 8 grok.implements(IHostelContainer) 9 grok.require('waeup.manageUniversity') 10 11 # A simple counter for ids. 12 next_id = 0L 13 14 def addHostel(self, hostel): 15 if not IHostel.providedBy(hostel): 16 raise TypeError('HostelContainers contain only IHostel instances') 17 id = str(self.next_id) 18 self[id] = hostel 19 while self.next_id in self.keys(): 20 # Look for next unused int... 21 self.next_id += 1 22 return id 23 24 class HostelContainerFactory(grok.GlobalUtility): 25 """A factory for faculty containers. 26 """ 27 grok.implements(IFactory) 28 grok.name(u'waeup.HostelContainer') 29 title = u"Create a new hostel container.", 30 description = u"This factory instantiates new hostel containers." 31 32 def __call__(self): 33 return HostelContainer() 34 35 def getInterfaces(self): 36 return implementedBy(HostelContainer) -
waeup/trunk/src/waeup/interfaces.py
r3526 r4789 1 1 ## 2 2 ## interfaces.py 3 from zope.interface import Interface 3 from zc.sourcefactory.basic import BasicSourceFactory 4 from zope.component import getUtility 5 from zope.app.catalog.interfaces import ICatalog 6 from zope.interface import Interface, Attribute 4 7 from zope import schema 5 6 class IUniversity(Interface): 8 from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm 9 from waeup.permissions import RoleSource 10 11 def SimpleWAeUPVocabulary(*terms): 12 """A well-buildt vocabulary provides terms with a value, token and 13 title for each term 14 """ 15 return SimpleVocabulary([ 16 SimpleTerm(value, value, title) for title, value in terms]) 17 18 19 class CourseSource(BasicSourceFactory): 20 """A course source delivers all courses inside the portal by looking 21 up a catalog. 22 """ 23 catalog = None 24 def getValues(self): 25 if self.catalog is None: 26 self.catalog = getUtility(ICatalog, name='courses_catalog') 27 return list(self.catalog.searchResults(code=('', 'z*'))) 28 29 def getTitle(self, value): 30 return "%s %s" % (value.code, value.title[:32]) 31 32 33 class IWAeUPObject(Interface): 34 """A WAeUP object. 35 """ 36 37 class IUniversity(IWAeUPObject): 7 38 """Representation of a university. 8 39 """ … … 12 43 required = True, 13 44 ) 45 46 faculties = Attribute("A container for faculties.") 47 students = Attribute("A container for students.") 48 hostels = Attribute("A container for hostels.") 49 50 class IWAeUPContainer(IWAeUPObject): 51 """A container for WAeUP objects. 52 """ 53 54 class IWAeUPContained(IWAeUPObject): 55 """An item contained in an IWAeUPContainer. 56 """ 57 58 class IStudentContainer(IWAeUPContainer): 59 """A container for StudentObjects. 60 """ 61 62 class IFaculty(IWAeUPContainer): 63 """Representation of a university faculty. 64 """ 65 title = schema.TextLine( 66 title = u'Name of Faculty', 67 default = u'Unnamed', 68 required = True, 69 ) 70 71 title_prefix = schema.TextLine( 72 title = u'Title prefix', 73 default = u'faculty', 74 required = True, 75 ) 76 77 code = schema.TextLine( 78 title = u'Code', 79 description = u'Abbreviated code of the faculty', 80 default = u'NA', 81 required = True, 82 ) 83 84 class IFacultyContainer(IWAeUPContainer): 85 """A container for faculties. 86 """ 87 def addFaculty(faculty): 88 """Add an IFactulty object. 89 90 Returns the key, under which the object was stored. 91 """ 92 93 class IHostelContainer(IWAeUPContainer): 94 """A container for hostels. 95 """ 96 def addHostel(hostel): 97 """Add an IHostel object. 98 99 Returns the key, under which the object was stored. 100 """ 101 102 class IHostel(IWAeUPObject): 103 """Representation of a hostel. 104 """ 105 name = schema.TextLine( 106 title = u'Name of Hostel', 107 default = u'Nobody', 108 required = True, 109 ) 110 111 class IDepartment(IWAeUPObject): 112 """Representation of a department. 113 """ 114 title = schema.TextLine( 115 title = u'Name of Department', 116 default = u'Unnamed', 117 required = True, 118 ) 119 120 title_prefix = schema.TextLine( 121 title = u'Title prefix', 122 default = u'department', 123 required = True, 124 ) 125 126 code = schema.TextLine( 127 title = u'Code', 128 default = u'NA', 129 description = u'Abbreviated code of the department', 130 required = True, 131 ) 132 133 courses = Attribute("A container for courses.") 134 certificates = Attribute("A container for certificates.") 135 136 137 class ICourseContainer(IWAeUPContainer): 138 """A container for faculties. 139 """ 140 def addCourse(faculty): 141 """Add an ICourse object. 142 143 Returns the key, under which the object was stored. 144 """ 145 146 class ICourse(IWAeUPObject): 147 """Representation of a course. 148 """ 149 code = schema.TextLine( 150 title = u'Code', 151 default = u'NA', 152 description = u'Abbreviated code of the course', 153 required = True, 154 readonly = True, 155 ) 156 157 title = schema.TextLine( 158 title = u'Title of course', 159 default = u'Unnamed', 160 required = True, 161 ) 162 163 level = schema.TextLine( 164 title = u'Level', 165 default = u'100', 166 required = False, 167 ) 168 169 credits = schema.Int( 170 title = u'Credits', 171 default = 0, 172 required = False, 173 ) 174 175 passmark = schema.Int( 176 title = u'Passmark', 177 default = 40, 178 required = False, 179 ) 180 181 semester = schema.Choice( 182 title = u'Semester/Term', 183 default = 0, 184 vocabulary = SimpleWAeUPVocabulary( 185 ('N/A', 0), ('First Semester', 1), 186 ('Second Semester', 2), ('Combined', 3)), 187 required = True, 188 ) 189 190 191 class ICertificate(IWAeUPObject): 192 """Representation of a certificate. 193 """ 194 code = schema.TextLine( 195 title = u'Code', 196 default = u'NA', 197 description = u'Abbreviated code of the certificate.', 198 required = True, 199 ) 200 201 review_state = schema.Choice( 202 title = u'review state', 203 values = ['unchecked', 'checked'] 204 ) 205 206 title = schema.TextLine( 207 title = u'title', 208 required = True, 209 ) 210 211 category = schema.TextLine( 212 title = u'category', 213 required = True, 214 ) 215 216 study_mode = schema.TextLine( 217 title = u'study mode', 218 required = True, 219 ) 220 221 start_level = schema.TextLine( 222 title = u'start level', 223 required = True, 224 ) 225 226 end_level = schema.TextLine( 227 title = u'end level', 228 required = True, 229 ) 230 231 application_category = schema.TextLine( 232 title = u'application category', 233 required = True, 234 ) 235 236 m_prefix = schema.TextLine( 237 title = u'prefix', 238 required = True, 239 ) 240 241 max_pass = schema.TextLine( 242 title = u'maximum pass', 243 required = True, 244 ) 245 246 247 248 class ICertificateContainer(IWAeUPContainer): 249 """A container for certificates. 250 """ 251 def addCertificate(faculty): 252 """Add an ICertificate object. 253 254 Returns the key, under which the object was stored. 255 """ 256 257 class ICertificateCourse(IWAeUPObject): 258 """A certificatecourse is a course referenced by a certificate, which 259 provides some own attributes. 260 """ 261 course = schema.Choice( 262 title = u'Course', 263 source = CourseSource(), 264 ) 265 266 level = schema.Int( 267 title = u'Level of this course', 268 required = True, 269 default = 100 270 ) 271 272 core_or_elective = schema.Bool( 273 title = u'Is mandatory course (not elective)', 274 required = True, 275 default = True 276 ) 277 278 def getCourseCode(): 279 """Return the code of the referenced course. 280 281 This is needed for cataloging. 282 """ 283 284 class IWAeUPExporter(Interface): 285 """An exporter for objects. 286 """ 287 def export(obj, filepath=None): 288 """Export by pickling. 289 290 Returns a file-like object containing a representation of `obj`. 291 292 This is done using `pickle`. If `filepath` is ``None``, a 293 `cStringIO` object is returned, that contains the saved data. 294 """ 295 296 class IWAeUPXMLExporter(Interface): 297 """An XML exporter for objects. 298 """ 299 def export(obj, filepath=None): 300 """Export as XML. 301 302 Returns an XML representation of `obj`. 303 304 If `filepath` is ``None``, a StringIO` object is returned, 305 that contains the transformed data. 306 """ 307 308 class IWAeUPXMLImporter(Interface): 309 """An XML import for objects. 310 """ 311 def doImport(filepath): 312 """Create Python object from XML. 313 314 Returns a Python object. 315 """ 316 317 class IWAeUPCSVExporter(Interface): 318 """A CSV exporter for objects. 319 """ 320 321 def export(obj, filepath=None): 322 """Export as CSV. 323 324 Returns a CSV representation of `obj`. 325 326 If `filepath` is ``None``, a StringIO` object is returned, 327 that contains the transformed data. 328 """ 329 330 class IWAeUPCSVImporter(Interface): 331 """A CSV importer for objects. 332 """ 333 datatype = schema.TextLine( 334 title = u'Data type', 335 description = u'Type of data supported by this filter.', 336 required = True,) 337 338 def doImport(clear_old_data=True, overwrite=True): 339 """Read data from `filepath` and apply data. 340 341 It depends on the context, what 'applying data' means here. 342 343 If `clear_old_data` is False, old data will be 344 preserved. Otherwise all old data will get lost. 345 346 If `overwrite` is False, any existing entries with similar 347 keys might be overwritten. This option is ignored, when 348 `clear_old_data` is set to True. 349 """ 350 351 class IUserAccount(IWAeUPObject): 352 """A user account. 353 """ 354 name = schema.TextLine( 355 title = u'User ID', 356 description = u'Loginname', 357 required = True,) 358 title = schema.TextLine( 359 title = u'Username', 360 description = u'Real name', 361 required = False,) 362 description = schema.TextLine( 363 title = u'User description', 364 required = False,) 365 password = schema.Password( 366 title = u'Password', 367 required = True,) 368 roles = schema.List( 369 title = u'Roles', 370 value_type = schema.Choice(source=RoleSource())) 371 372 373 class IUserContainer(IWAeUPObject): 374 """A container for users (principals). 375 376 These users are used for authentication purposes. 377 """ 378 379 def addUser(name, password, title=None, description=None): 380 """Add a user. 381 """ 382 383 def delUser(name): 384 """Delete a user if it exists. 385 """ 386 387 class IDataCenter(IWAeUPObject): 388 """A data center. 389 390 TODO : declare methods, at least those needed by pages. 391 """ 392 pass 393 394 class ICSVDataReceivers(Interface): 395 """An object containing things ready for CSV imports. 396 397 This is pure marker interface. Objects that implement it, indicate 398 that they might provide attributes, which are able to receive CSV 399 data, i.e. for which an IWAeUPCSVDataImporter exists. 400 """ 401 402 class IDataCenterFile(Interface): 403 """A data center file. 404 """ 405 def getDate(): 406 """Get creation timestamp from file in human readable form. 407 """ 408 409 def getSize(): 410 """Get human readable size of file. 411 """ -
waeup/trunk/src/waeup/permissions.py
r3521 r4789 1 1 import grok 2 from zc.sourcefactory.basic import BasicSourceFactory 2 3 4 class Public(grok.Permission): 5 """Everyone-can-do-this-permission. 6 7 This permission is meant to be applied to objects/views/pages 8 etc., that should be usable/readable by everyone. 9 10 We need this to be able to tune default permissions more 11 restrictive and open up some dedicated objects like the front 12 page. 13 """ 14 grok.name('waeup.Public') 15 16 class ViewPermission(grok.Permission): 17 grok.name('waeup.View') 18 19 class ManageUniversity(grok.Permission): 20 grok.name('waeup.manageUniversity') 21 22 class ManageUsers(grok.Permission): 23 grok.name('waeup.manageUsers') 24 3 25 class FacultyRead(grok.Permission): 4 26 grok.name('waeup.facultyread') 27 28 class PortalUser(grok.Role): 29 grok.name('waeup.PortalUser') 30 grok.permissions('waeup.facultyread', 'waeup.View', 'waeup.Public') 5 31 32 class PortalManager(grok.Role): 33 grok.name('waeup.PortalManager') 34 grok.permissions('waeup.manageUniversity', 'waeup.manageUsers', 35 'waeup.View', 'waeup.Public') 36 37 def getRoles(): 38 app = grok.getSite() 39 app = None 40 manager = None 41 if app is not None: 42 from zope.securitypolicy.interfaces import IRolePermissionManager 43 manager = IRolePermissionManager(app, None) 44 else: 45 from zope.securitypolicy.rolepermission import ( 46 rolePermissionManager as manager) 47 role_permission_map = manager.getRolesAndPermissions() 48 result = dict() 49 for item in role_permission_map: 50 if not item[1].startswith('waeup.'): 51 # Ignore non-WAeUP roles... 52 continue 53 result[item[1]] = True 54 return sorted(result.keys()) 55 56 class RoleSource(BasicSourceFactory): 57 def getValues(self): 58 return getRoles() 59 def getTitle(self, value): 60 if isinstance(value, basestring): 61 return value.split('.', 2)[1] -
waeup/trunk/src/waeup/static/app.css
r3530 r4789 8 8 } 9 9 10 #uni-title { 11 font-size: 24px; 12 font-weight: bold; 13 padding-top: 20px; 14 position: absolute; 15 } 16 17 #yui-gen1 { 18 background-color: #FFEEBB; 19 border: 3px; 20 } 21 22 23 div.yui-layout-bd-nohd { 24 background-color: #0f0; 25 border: 0px; 26 } 27 28 .actionbarlink { 29 background-color: #feb; 30 padding: 3px; 31 text-align: center; 32 } 33 34 .actionbarlink a{ 35 text-decoration: underline; 36 } 37 38 .actionbarlink img { 39 position: absolute; 40 } 41 42 .actionbarlink span { 43 padding-left: 20px; 44 } 45 46 .yui-link-button img { 47 position: absolute; 48 padding-top: 5px; 49 } 50 51 .yui-link-button a span { 52 padding-left: 20px; 53 } 54 10 55 h1,h2,h3 { 11 56 color: #005500; 12 font-weight: normal; 57 font-weight: bold; 58 font-size: 120%; 59 border-bottom: 1px solid; 13 60 } 14 61 … … 17 64 } 18 65 19 a:hover {66 a:hovers { 20 67 text-decoration: underline; 21 68 } … … 62 109 */ 63 110 font-size: x-small; 111 text-align: center; 64 112 } 65 113 … … 120 168 font-size: small; 121 169 } 170 171 .message { 172 background-color: #fe0; 173 color: #000; 174 text-align: center; 175 font-weight: bold; 176 padding: 2px; 177 padding-right: 10px; 178 border: 1px dotted #050; 179 } 180 181 .yui-skin-sam .yui-layout .yui-layout-clip { 182 /* collapsed unit */ 183 background-color: #edc; 184 } 185 186 .yui-layout, .yui-layout-doc { 187 background-color: #feb; 188 } 189 190 .yui-layout-wrap, .yui-layout-bd, .yui-layout-clip { 191 backgr/ound-color: #feb; 192 } 193 194 div.yui-layout-bd-nohd { 195 background-color: #ffc; 196 } 197 198 .yui-layout-unit { 199 background-color: #feb; 200 } 201 202 #alayout-doc { 203 background-color: #FFEEBB; 204 } 205 206 #div, .yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd { 207 208 } 209 210 .yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd { 211 /* asd */ 212 background-color: #ffc; 213 } 214 215 #innermain { 216 padding: 5px; 217 } 218 219 .yui-skin-sam .yui-resize .yui-resize-handle { 220 background-color: #feb; 221 } 222 223 #hd { 224 padding: 5px; 225 } 226 227 th, td { 228 font-family: arial, sans-serif; 229 } -
waeup/trunk/src/waeup/testing.py
r3521 r4789 5 5 ftesting_zcml = os.path.join( 6 6 os.path.dirname(waeup.__file__), 'ftesting.zcml') 7 FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer') 7 FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer', 8 allow_teardown=True) -
waeup/trunk/src/waeup/tests/test_waeup.py
r3521 r4789 5 5 """ 6 6 import grok 7 import zope.component.eventtesting 8 from waeup.testing import FunctionalLayer 9 10 def setUpZope(test): 11 zope.component.eventtesting.setUp(test) 12 7 13 # Register all tests in the waeup_ng package 8 14 test_suite = grok.testing.register_all_tests( 9 'waeup') 15 'waeup', usetup=setUpZope, 16 layer=FunctionalLayer) -
waeup/trunk/src/waeup/university/__init__.py
r3521 r4789 1 # Make this a package. -
waeup/trunk/src/waeup/university/certificate.py
r3526 r4789 1 """WAeUP portal certificates 2 """ 3 import grok 4 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState 5 from zope.app.catalog.interfaces import ICatalog 6 from zope.component import getUtility 7 from zope.component.interfaces import IFactory, ComponentLookupError 8 from zope.interface import implementedBy 9 from waeup.interfaces import ICertificate, ICertificateCourse, ICourse 10 11 class Certificate(grok.Container): 12 """A certificate. 13 """ 14 grok.implements(ICertificate) 15 16 def __init__(self, code=u'NA', title=u'Unnamed Certificate', 17 category=None, study_mode=None, start_level=None, 18 end_level=None, application_category=None, m_prefix=u'', 19 max_pass = u''): 20 super(Certificate, self).__init__() 21 self.code = code 22 self.title = title 23 self.category = category 24 self.study_mode = study_mode 25 self.start_level = start_level 26 self.end_level = end_level 27 self.application_category = application_category 28 self.m_prefix = m_prefix 29 self.max_pass = max_pass 30 # Initialize workflow state... 31 self.setReviewState('unchecked') 32 33 def check(self): 34 """Set Review State to ``checked``. 35 """ 36 self.setReviewState(state='checked') 37 38 def getReviewState(self): 39 return IWorkflowState(self).getState() 40 41 def setReviewState(self, state=None): 42 """Try to set new state. 43 44 Instead of simply setting a value, we fire a transition of a 45 workflow. This might fail if, for instance, the required state 46 is not part of the workflow or unreachable from current state. 47 """ 48 if state == self.getReviewState(): 49 # Accept staying in the same state, even if workflow does 50 # not allow this. 51 return 52 info = IWorkflowInfo(self) 53 info.fireTransitionToward(state) 54 return 55 56 review_state = property(getReviewState, setReviewState) 57 58 def addCourseRef(self, course, level=100, core_or_elective=True): 59 """Add a course reference. 60 """ 61 code = "%s_%s" % (course.code, level) 62 self[code] = CertificateCourse(course, level, core_or_elective) 63 self[code].__parent__ = self 64 self[code].__name__ = code 65 self._p_changed = True 66 67 def delCourseRef(self, code, level=None): 68 """Delete a course denoted by its code. 69 """ 70 for key in self.keys(): 71 if self[key].getCourseCode() != code: 72 continue 73 if level is not None and str(self[key].level) != str(level): 74 # found a course with correct key but wrong level... 75 continue 76 del self[key] 77 self._p_changed = True 78 return 79 80 81 82 83 class CertificateFactory(grok.GlobalUtility): 84 """A factory for certificates. 85 """ 86 grok.implements(IFactory) 87 grok.name(u'waeup.Certificate') 88 title = u"Create a new certificate.", 89 description = u"This factory instantiates new certificate instances." 90 91 def __call__(self, *args, **kw): 92 return Certificate(*args, **kw) 93 94 def getInterfaces(self): 95 return implementedBy(Certificate) 96 97 class CertificateCourse(grok.Model): 98 grok.implements(ICertificateCourse) 99 100 def __init__(self, course=None, level=100, core_or_elective=True): 101 self.course = course 102 self.level = level 103 self.core_or_elective = core_or_elective 104 105 def getCourseCode(self): 106 """Get code of a course. 107 """ 108 return self.course.code 109 110 class CertificateCourseFactory(grok.GlobalUtility): 111 """A factory for certificate courses. 112 """ 113 grok.implements(IFactory) 114 grok.name(u'waeup.CertificateCourse') 115 title = u"Create a new certificate course.", 116 description = u"This factory instantiates new certificate courses." 117 118 def __call__(self, *args, **kw): 119 return CertificateCourse(*args, **kw) 120 121 def getInterfaces(self): 122 return implementedBy(CertificateCourse) 123 124 @grok.subscribe(ICourse, grok.IObjectRemovedEvent) 125 def removedCourseHandler(course, event): 126 """If a course is deleted, we make sure that also references in a 127 certificatecontainer are removed. 128 """ 129 code = course.code 130 131 # Find all certcourses that reference the given course... 132 try: 133 cat = getUtility(ICatalog, name='certcourses_catalog') 134 except ComponentLookupError: 135 # catalog not available. This might happen during tests. 136 return 137 138 results = cat.searchResults(course_code=(code, code)) 139 for certcourse in results: 140 # Remove that reference... 141 cert = certcourse.__parent__ 142 cert.delCourseRef(code) 143 cert._p_changed = True 144 return -
waeup/trunk/src/waeup/university/course.py
r3526 r4789 1 """Courses. 2 """ 3 import grok 4 from zope.interface import implementedBy 5 from zope.component.interfaces import IFactory 6 from waeup.interfaces import ICourse 7 8 class Course(grok.Model): 9 """A university course. 10 """ 11 grok.implements(ICourse) 12 13 def __init__(self, 14 title=u'Unnamed Course', 15 code=u'NA', 16 level=None, 17 credits=0, 18 passmark=40, 19 semester=1, **kw): 20 super(Course, self).__init__(**kw) 21 self.title = title 22 self.code = code 23 self.level = level 24 self.credits = credits 25 self.passmark = passmark 26 self.semester = semester 27 28 class CourseFactory(grok.GlobalUtility): 29 """A factory for courses. 30 """ 31 grok.implements(IFactory) 32 grok.name(u'waeup.Course') 33 title = u"Create a new course.", 34 description = u"This factory instantiates new course instances." 35 36 def __call__(self, *args, **kw): 37 return Course(*args, **kw) 38 39 def getInterfaces(self): 40 return implementedBy(Course) -
waeup/trunk/src/waeup/university/department.py
r3526 r4789 1 """University departments. 2 """ 3 import grok 4 from zope.component import createObject 5 from zope.component.interfaces import IFactory 6 from zope.interface import implementedBy 7 from waeup.interfaces import IDepartment 8 9 class Department(grok.Container): 10 """A university department. 11 """ 12 grok.implements(IDepartment) 13 14 # A simple counter for ids. 15 next_id = 0L 16 17 def __init__(self, 18 title=u'Unnamed Department', 19 title_prefix=u'department', 20 code=u"NA", **kw): 21 super(Department, self).__init__(**kw) 22 self.title = title 23 self.title_prefix = title_prefix 24 self.code = code 25 self.courses = createObject(u'waeup.CourseContainer') 26 self.courses.__parent__ = self 27 self.courses.__name__ = 'courses' 28 self.certificates = createObject(u'waeup.CertificateContainer') 29 self.certificates.__parent__ = self 30 self.certificates.__name__ = 'certificates' 31 32 def traverse(self, name): 33 """Deliver appropriate containers, if someone wants to go to courses 34 or departments. 35 """ 36 if name == 'courses': 37 return self.courses 38 elif name == 'certificates': 39 return self.certificates 40 return None 41 42 43 class DepartmentFactory(grok.GlobalUtility): 44 """A factory for department containers. 45 """ 46 grok.implements(IFactory) 47 grok.name(u'waeup.Department') 48 title = u"Create a new department.", 49 description = u"This factory instantiates new department instances." 50 51 def __call__(self, *args, **kw): 52 return Department(*args, **kw) 53 54 def getInterfaces(self): 55 """Get interfaces of objects provided by this factory. 56 """ 57 return implementedBy(Department) -
waeup/trunk/src/waeup/university/faculty.py
r3529 r4789 1 """Faculty components. 2 """ 3 1 4 import grok 2 from waeup.basecontainer import BaseContainer 3 from interfaces import IFaculty 5 from zope.component.interfaces import IFactory 6 from zope.interface import implementedBy 7 from waeup.interfaces import IFaculty, IDepartment 4 8 5 class Faculty(BaseContainer): 9 class Faculty(grok.Container): 10 """A university faculty. 11 """ 6 12 grok.implements(IFaculty) 7 13 8 def __init__(self, name=u'Unnamed Faculty', **kw): 14 def __init__(self, 15 title=u'Unnamed Faculty', 16 title_prefix=u'faculty', 17 code=u'NA', **kw): 9 18 super(Faculty, self).__init__(**kw) 10 self.name = name 19 self.title = title 20 self.title_prefix = title_prefix 21 self.code = code 11 22 12 class Index(grok.DisplayForm): 13 form_fields = grok.AutoFields(IFaculty) 23 def addDepartment(self, department): 24 """Add a department to the faculty. 25 """ 26 if not IDepartment.providedBy(department): 27 raise TypeError('Faculties contain only IDepartment instances') 28 self[department.code] = department 14 29 30 def clear(self): 31 """Remove all departments from faculty. 32 """ 33 keys = self.keys() 34 for key in keys: 35 del self[key] 15 36 37 def getName(self, key): 38 """Get complete faculty name. 39 """ 40 if key in self.keys(): 41 dept = self[key] 42 prefix = dept.title_prefix 43 prefix = prefix[0].upper() + prefix[1:] 44 return '%s of %s' % (prefix, dept.title) 45 46 47 class FacultyFactory(grok.GlobalUtility): 48 """A factory for faculty containers. 49 """ 50 grok.implements(IFactory) 51 grok.name(u'waeup.Faculty') 52 title = u"Create a new faculty.", 53 description = u"This factory instantiates new faculty instances." 54 55 def __call__(self, *args, **kw): 56 return Faculty() 57 58 def getInterfaces(self): 59 return implementedBy(Faculty) -
waeup/trunk/src/waeup/university/facultycontainer.py
r3527 r4789 1 1 import grok 2 from waeup.basecontainer import BaseContainer3 from interfaces import IFaculty4 from faculty importFaculty2 from zope.component.interfaces import IFactory 3 from zope.interface import implementedBy 4 from waeup.interfaces import IFacultyContainer, IFaculty 5 5 6 class FacultyContainer(BaseContainer): 7 8 name = u'Faculties' 9 childClass = Faculty 6 class FacultyContainer(grok.Container): 7 """See interfaces for description. 8 """ 9 grok.implements(IFacultyContainer) 10 grok.require('waeup.manageUniversity') 11 12 def addFaculty(self, faculty): 13 if not IFaculty.providedBy(faculty): 14 raise TypeError('FacultyContainers contain only IFaculty instances') 15 self[faculty.code] = faculty 16 return 17 18 def clear(self): 19 keys = self.keys() 20 for key in keys: 21 del self[key] 22 23 def getName(self, key): 24 if key in self.keys(): 25 fac = self[key] 26 prefix = fac.title_prefix 27 prefix = prefix[0].upper() + prefix[1:] 28 return '%s of %s' % (prefix, fac.title) 29 30 class FacultyContainerFactory(grok.GlobalUtility): 31 """A factory for faculty containers. 32 """ 33 grok.implements(IFactory) 34 grok.name(u'waeup.FacultyContainer') 35 title = u"Create a new faculty container.", 36 description = u"This factory instantiates new faculty containers." 37 38 def __call__(self): 39 return FacultyContainer() 40 41 def getInterfaces(self): 42 return implementedBy(FacultyContainer) -
waeup/trunk/src/waeup/utils/importexport.py
r3529 r4789 1 import re 1 2 import csv 3 import grok 4 import cPickle 5 import zope.xmlpickle 6 from cStringIO import StringIO 7 from xml.dom.minidom import Document, getDOMImplementation 8 from zope.interface import Interface 9 from waeup.csvfile.interfaces import ICSVFile 10 from waeup.interfaces import (IWAeUPObject, IWAeUPExporter, IWAeUPXMLExporter, 11 IWAeUPXMLImporter, IWAeUPCSVImporter) 2 12 3 13 def readFile(f): … … 14 24 writer = csv.writer(open("export.csv", "wb")) 15 25 writer.writerows(data) 26 27 class Exporter(grok.Adapter): 28 """Export a WAeUP object as pickle. 29 30 This all-purpose exporter exports attributes defined in schemata 31 and contained objects (if the exported thing is a container). 32 """ 33 grok.context(IWAeUPObject) 34 grok.provides(IWAeUPExporter) 35 36 def __init__(self, context): 37 self.context = context 38 39 def export(self, filepath=None): 40 if filepath is None: 41 filelike_obj = StringIO() 42 else: 43 filelike_obj = open(filepath, 'wb') 44 exported_obj = cPickle.dump(self.context, filelike_obj) 45 filelike_obj.close() 46 return filelike_obj 47 48 class XMLExporter(grok.Adapter): 49 """Export a WAeUP object as XML. 50 51 This all-purpose exporter exports XML representations of pickable 52 objects. 53 """ 54 grok.context(Interface) 55 grok.provides(IWAeUPXMLExporter) 56 57 def __init__(self, context): 58 self.context = context 59 60 def export(self, filepath=None): 61 pickled_obj = cPickle.dumps(self.context) 62 result = zope.xmlpickle.toxml(pickled_obj) 63 if filepath is None: 64 filelike_obj = StringIO() 65 else: 66 filelike_obj = open(filepath, 'wb') 67 filelike_obj.write(result) 68 filelike_obj.seek(0) 69 return filelike_obj 70 71 class XMLImporter(grok.Adapter): 72 """Import a WAeUP object from XML. 73 """ 74 grok.context(Interface) 75 grok.provides(IWAeUPXMLImporter) 76 77 def __init__(self, context): 78 self.context = context 79 80 def doImport(self, filepath): 81 xml = None 82 if isinstance(filepath, basestring): 83 xml = open(filepath, 'rb').read() 84 else: 85 xml = filepath.read() 86 obj = zope.xmlpickle.loads(xml) 87 return obj 88 89 90 class CSVImporter(grok.MultiAdapter): 91 grok.adapts(ICSVFile, IWAeUPObject) 92 grok.provides(IWAeUPCSVImporter) 93 grok.baseclass() # We don't want this base to be registered really. 94 95 def __init__(self, csvfile, receiver): 96 self.csvfile = csvfile 97 self.receiver = receiver 98 99 def doImport(self): 100 pass
Note: See TracChangeset for help on using the changeset viewer.