schooltool.cando-2.6.2/ 0000755 0001750 0001750 00000000000 12322040274 016115 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/base.cfg 0000644 0001750 0001750 00000003222 12270520445 017514 0 ustar menesis menesis 0000000 0000000 [buildout]
extends = http://ftp.schooltool.org/schooltool/trunk/versions.cfg
versions = versions
newest = false
find-links =
http://ftp.schooltool.org/schooltool/trunk/
http://ftp.schooltool.org/schooltool/trunk/dev/
parts = package test supervisor celery scripts ctags omelette
[package]
recipe = zc.recipe.egg:eggs
unzip = true
# set eggs to package name in buildout.cfg
eggs =
[scripts]
recipe = zc.recipe.egg:scripts
unzip = true
eggs =
${package:eggs}
ZODB3
redis
schooltool
schooltool.devtools
scripts = # ZODB3:
runzeo
zeopack
# schooltool.devtools:
i18nextract
runfdoctests
# schooltool:
make-schooltool-instance
start-schooltool-instance
schooltool-server
interpreter = python
[supervisor]
recipe = zc.recipe.egg:scripts
unzip = true
eggs = supervisor
scripts = supervisord
supervisorctl
pidproxy
# Useful script if you want to toy with supervisor settings
#echo_supervisord_conf
initialization =
import os
if os.path.exists('instance'): os.chdir('instance')
[celery]
recipe = zc.recipe.egg:scripts
unzip = true
eggs = ${package:eggs}
celery
redis
scripts = # celery:
#celerybeat
celeryd
celeryev
celeryctl
#camqadm
#celeryd-multi
[test]
recipe = schooltool.devtools:testrunner
eggs = ${package:eggs}
defaults = ['--tests-pattern', '^f?s?tests$', '-v', '--auto-color']
[ctags]
recipe = z3c.recipe.tag:tags
eggs = ${test:eggs}
[omelette]
recipe = collective.recipe.omelette
eggs = ${test:eggs}
ignores = roman zope.ucol site
schooltool.cando-2.6.2/buildout.cfg 0000644 0001750 0001750 00000000304 12322040274 020422 0 ustar menesis menesis 0000000 0000000 [buildout]
extends = base.cfg
develop = .
[versions]
# Unset versions of packages you want to develop
schooltool.cando =
[package]
eggs = schooltool.cando
[test]
eggs = schooltool.cando [test]
schooltool.cando-2.6.2/develop.cfg 0000644 0001750 0001750 00000000176 12270520445 020245 0 ustar menesis menesis 0000000 0000000 [buildout]
extends = deploy.cfg
parts += coverage
[coverage]
recipe = zc.recipe.egg:scripts
unzip = true
eggs = z3c.coverage
schooltool.cando-2.6.2/src/ 0000755 0001750 0001750 00000000000 12322040274 016704 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool.cando.egg-info/ 0000755 0001750 0001750 00000000000 12322040274 023646 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool.cando.egg-info/SOURCES.txt 0000644 0001750 0001750 00000016535 12322040274 025544 0 ustar menesis menesis 0000000 0000000 CHANGES.txt
GPL.txt
MANIFEST.in
Makefile
README.txt
base.cfg
bootstrap.py
buildout.cfg
deploy.cfg
develop.cfg
setup.py
version.txt.in
src/schooltool/__init__.py
src/schooltool.cando.egg-info/PKG-INFO
src/schooltool.cando.egg-info/SOURCES.txt
src/schooltool.cando.egg-info/dependency_links.txt
src/schooltool.cando.egg-info/entry_points.txt
src/schooltool.cando.egg-info/namespace_packages.txt
src/schooltool.cando.egg-info/not-zip-safe
src/schooltool.cando.egg-info/requires.txt
src/schooltool.cando.egg-info/top_level.txt
src/schooltool/cando/__init__.py
src/schooltool/cando/configure.zcml
src/schooltool/cando/course.py
src/schooltool/cando/course.zcml
src/schooltool/cando/gradebook.py
src/schooltool/cando/gradebook.zcml
src/schooltool/cando/iep.py
src/schooltool/cando/iep.zcml
src/schooltool/cando/interfaces.py
src/schooltool/cando/model.py
src/schooltool/cando/model.zcml
src/schooltool/cando/plugin.zcml
src/schooltool/cando/project.py
src/schooltool/cando/project.zcml
src/schooltool/cando/security.zcml
src/schooltool/cando/skill.py
src/schooltool/cando/skill.zcml
src/schooltool/cando/stesting.py
src/schooltool/cando/stesting.zcml
src/schooltool/cando/translations.zcml
src/schooltool/cando/browser/__init__.py
src/schooltool/cando/browser/breadcrumbs.py
src/schooltool/cando/browser/breadcrumbs.zcml
src/schooltool/cando/browser/configure.zcml
src/schooltool/cando/browser/course.py
src/schooltool/cando/browser/document.py
src/schooltool/cando/browser/document.zcml
src/schooltool/cando/browser/gradebook.py
src/schooltool/cando/browser/gradebook.zcml
src/schooltool/cando/browser/iep.py
src/schooltool/cando/browser/iep.zcml
src/schooltool/cando/browser/importer.py
src/schooltool/cando/browser/model.py
src/schooltool/cando/browser/report.py
src/schooltool/cando/browser/report.zcml
src/schooltool/cando/browser/request_reports.py
src/schooltool/cando/browser/skill.py
src/schooltool/cando/browser/xls_views.py
src/schooltool/cando/browser/resources/cando.css
src/schooltool/cando/browser/resources/cando.js
src/schooltool/cando/browser/resources/empty_skills_data.xls
src/schooltool/cando/browser/resources/ui-icons_222222_256x240.png
src/schooltool/cando/browser/resources/ui-icons_ffffff_256x240.png
src/schooltool/cando/browser/rml/competency_certificate_signature.pt
src/schooltool/cando/browser/rml/competency_certificate_styles.pt
src/schooltool/cando/browser/rml/section_student_scr.pt
src/schooltool/cando/browser/rml/student_competency_report_styles.pt
src/schooltool/cando/browser/stests/__init__.py
src/schooltool/cando/browser/stests/add_skills.txt
src/schooltool/cando/browser/stests/cando_tab.txt
src/schooltool/cando/browser/stests/course_nodes.xls
src/schooltool/cando/browser/stests/course_skills.txt
src/schooltool/cando/browser/stests/course_skills.xls
src/schooltool/cando/browser/stests/delete_current_worksheet.txt
src/schooltool/cando/browser/stests/deprecate.txt
src/schooltool/cando/browser/stests/gradebook_grade_student.txt
src/schooltool/cando/browser/stests/gradebook_management.txt
src/schooltool/cando/browser/stests/gradebook_multiple_term.txt
src/schooltool/cando/browser/stests/gradebook_skill_labels.txt
src/schooltool/cando/browser/stests/iep.txt
src/schooltool/cando/browser/stests/iep_scr.txt
src/schooltool/cando/browser/stests/import_skills.txt
src/schooltool/cando/browser/stests/label_constraints.txt
src/schooltool/cando/browser/stests/label_title_sorting.txt
src/schooltool/cando/browser/stests/layer_hierarchy.txt
src/schooltool/cando/browser/stests/nodes_layers.txt
src/schooltool/cando/browser/stests/per_student_skills_report.txt
src/schooltool/cando/browser/stests/per_student_skills_report_multiple_term.txt
src/schooltool/cando/browser/stests/projects.txt
src/schooltool/cando/browser/stests/sample_data.xls
src/schooltool/cando/browser/stests/skill_events.txt
src/schooltool/cando/browser/stests/skill_events_importer.txt
src/schooltool/cando/browser/stests/skill_events_importer.xls
src/schooltool/cando/browser/stests/skill_scoresystems.txt
src/schooltool/cando/browser/stests/skillsets_skills.txt
src/schooltool/cando/browser/stests/test_selenium.py
src/schooltool/cando/browser/templates/aggregate_filter.pt
src/schooltool/cando/browser/templates/cando_resources.pt
src/schooltool/cando/browser/templates/cando_third_nav.pt
src/schooltool/cando/browser/templates/colorcodes_help.pt
src/schooltool/cando/browser/templates/course_assign_skills_table_filter.pt
src/schooltool/cando/browser/templates/course_assign_skillsets_dialog.pt
src/schooltool/cando/browser/templates/course_remove_skills.pt
src/schooltool/cando/browser/templates/course_skills_edit.pt
src/schooltool/cando/browser/templates/course_skills_edit_table_buttons.pt
src/schooltool/cando/browser/templates/course_skills_overview.pt
src/schooltool/cando/browser/templates/course_skillset.pt
src/schooltool/cando/browser/templates/courses_skills_assignment.pt
src/schooltool/cando/browser/templates/dialog_button_column.pt
src/schooltool/cando/browser/templates/document.pt
src/schooltool/cando/browser/templates/document_add.pt
src/schooltool/cando/browser/templates/document_skill.pt
src/schooltool/cando/browser/templates/document_skillset.pt
src/schooltool/cando/browser/templates/edit_course_skills.pt
src/schooltool/cando/browser/templates/f_import_related.pt
src/schooltool/cando/browser/templates/filldown_dialog.pt
src/schooltool/cando/browser/templates/form.pt
src/schooltool/cando/browser/templates/gradebook_iep_students.pt
src/schooltool/cando/browser/templates/gradebook_skills_dialog.pt
src/schooltool/cando/browser/templates/iep_details.pt
src/schooltool/cando/browser/templates/iep_sections.pt
src/schooltool/cando/browser/templates/layer.pt
src/schooltool/cando/browser/templates/node.pt
src/schooltool/cando/browser/templates/nodes_table_filter.pt
src/schooltool/cando/browser/templates/project_skill_table_filter.pt
src/schooltool/cando/browser/templates/projects.pt
src/schooltool/cando/browser/templates/request_competency_certificate.pt
src/schooltool/cando/browser/templates/retire_nodes_save_button.pt
src/schooltool/cando/browser/templates/retire_nodes_script.pt
src/schooltool/cando/browser/templates/scoresystem_help.pt
src/schooltool/cando/browser/templates/section_report_charts_column.pt
src/schooltool/cando/browser/templates/section_report_details.pt
src/schooltool/cando/browser/templates/section_report_score_colors.pt
src/schooltool/cando/browser/templates/section_report_score_colors_column.pt
src/schooltool/cando/browser/templates/section_report_script.pt
src/schooltool/cando/browser/templates/skill.pt
src/schooltool/cando/browser/templates/skill_edit.pt
src/schooltool/cando/browser/templates/skillset.pt
src/schooltool/cando/browser/templates/skillsets.pt
src/schooltool/cando/browser/tests/__init__.py
src/schooltool/cando/generations/__init__.py
src/schooltool/cando/generations/evolve1.py
src/schooltool/cando/generations/evolve2.py
src/schooltool/cando/generations/evolve3.py
src/schooltool/cando/generations/install.py
src/schooltool/cando/locales/__init__.py
src/schooltool/cando/locales/es_SV.po
src/schooltool/cando/locales/nl.po
src/schooltool/cando/locales/schooltool.cando.pot
src/schooltool/cando/locales/th.po
src/schooltool/cando/locales/es_SV/LC_MESSAGES/schooltool.cando.mo
src/schooltool/cando/locales/nl/LC_MESSAGES/schooltool.cando.mo
src/schooltool/cando/locales/th/LC_MESSAGES/schooltool.cando.mo
src/schooltool/cando/tests/__init__.py
src/schooltool/cando/tests/test_model.py
src/schooltool/cando/tests/test_skill.py schooltool.cando-2.6.2/src/schooltool.cando.egg-info/top_level.txt 0000644 0001750 0001750 00000000013 12322040274 026372 0 ustar menesis menesis 0000000 0000000 schooltool
schooltool.cando-2.6.2/src/schooltool.cando.egg-info/entry_points.txt 0000644 0001750 0001750 00000000106 12322040274 027141 0 ustar menesis menesis 0000000 0000000
[z3c.autoinclude.plugin]
target = schooltool
schooltool.cando-2.6.2/src/schooltool.cando.egg-info/PKG-INFO 0000644 0001750 0001750 00000017453 12322040274 024755 0 ustar menesis menesis 0000000 0000000 Metadata-Version: 1.1
Name: schooltool.cando
Version: 2.6.2
Summary: CanDo plugin for SchoolTool
Home-page: http://www.schooltool.org
Author: SchoolTool Developers
Author-email: schooltool-developers@lists.launchpad.net
License: GPL
Description:
=======
CHANGES
=======
2.6.2 (2014-04-11)
------------------
- Fixed access to scoresDict property (https://launchpad.net/bugs/1306778)
2.6.1 (2013-11-24)
------------------
- Fixed equivalent lookup in the skills gradebook.
- Fix Total points external activity to return a percentage of total possible
points.
2.6.0 (2013-10-10)
------------------
- Add student's view for projects (https://launchpad.net/bugs/1070278)
- Fix student and teacher sorting in some reports.
- Allow sorting gradebook by first or last name (https://launchpad.net/bugs/1234284)
- Fix navigation when schoolear has non-ascii chars (https://launchpad.net/bugs/1234690)
- Fix forbidden attribute error on login after timeout (https://launchpad.net/bugs/1154662)
0.8.2 (2013-09-14)
------------------
- Add a view to batch-deprecate skills, skill sets and nodes.
- Added field to node search table to filter by common text
- Fixed Save button in deprecate skills view when there's only one result
- Changed wording and functionality of Visible/Active/Retired to Deprecated
- Changed wording attribute to field in batch assign view
- Fixed score student view for projects
0.8.1 (2013-08-23)
------------------
- Nodes and skill sets can now be retired.
- Allow clerks and managers to access skills and reports.
- Update GPL license and file headers from gnu.org (https://launchpad.net/bugs/1211145)
0.8.0 (2013-08-01)
------------------
- Background PDF reports
- Moved in Per Student Skills Report and Skills Completion Report from schooltool.virginia
- Added Student skill completion (by section) pdf archive report.
0.7.1 (2013-05-29)
------------------
- Renamed Section Competencies reports to Student Skill Reports
- Fixed Add Skill exception when z3c.form >= 2.9 is used (https://launchpad.net/bugs/1185433)
0.7.0 (2013-04-18)
------------------
- Fixed column title in SkillSets worksheet in sample data xls (https://launchpad.net/bugs/1126624)
- Added Label column to SkillSets worksheet in the exporter
- Changed required widget terms to Required and Optional (https://launchpad.net/bugs/1123471)
- Made label and descriptions fields uniform for nodes, skill sets and skills (https://launchpad.net/bugs/1103708)
- Added "Submit and add" action to "New skill set" form (https://launchpad.net/bugs/1103710)
- Changed Skills selector to Skill Sets in the gradebook (https://launchpad.net/bugs/1154425)
- Fixed worksheet order in Skills Export xls (https://launchpad.net/bugs/1126612)
- Updated translations
0.6.2 (2013-03-25)
------------------
- Added section student competency report
- Fixed skills sorting in Set Required/Visible view
- Fixed permissions of project view
0.6.1 (2013-03-20)
------------------
- Fixed permissions of popup menus and competency report
- Updated translations, added Thai
0.6 (2013-02-25)
----------------
- Fix section skills with no equivalent course skill
- Sorted by label and title in add skill view for projects
- Moved "Skills Export" option from School to Documents view (https://launchpad.net/bugs/1126577)
- Moved "Import Skill Data" option from School to Documents view (https://launchpad.net/bugs/1131436)
- Changed string "skillset" to "skill set" (https://launchpad.net/bugs/1131376)
- Removed title from tables in index views for document and node (https://launchpad.net/bugs/1049966)
0.5.1 (2013-02-18)
------------------
- New-style CanDo Gradebook report.
- Added student's Section Competencies report.
- Added student's Certificate of Competency report.
0.4.4 (2013-02-18)
------------------
- Fixed error when current skillset for the user has been removed.
- Sorted tables for adding/removing nodes by label and title.
0.4.3 (2013-02-11)
------------------
- Fixed submit of Set Required/Visible course skills page.
0.4.2 (2013-01-29)
------------------
- Skills now have their own scoresystem. Old skills that had no scoresystem
set, system default is used.
- Add IEP (Individualized Educational Plan) functionality.
- Added Dutch and Spanish (El Salvador) translations.
0.4.1 (2012-11-29)
------------------
- Fixed skills sorting in more teacher and student views.
- Update section worksheets on global skill or skillset change (https://launchpad.net/bugs/1066940)
0.4 (2012-11-27)
----------------
- Search skills, skillsets, or nodes.
- Sorted components (skills, skill sets, layers, etc) by label and title
0.3.2 (2012-11-09)
------------------
- Fix for the missing scores fix
0.3.1 (2012-11-08)
------------------
- Sorted skills by label in the skills gradebook
- Fixed validation in score student view
- Removed subscriber that prevented section deleting
- Restored scores that disappeared after upgrade to 0.3
0.3 (2012-10-19)
----------------
- New sections don't get existing course skills (https://launchpad.net/bugs/1065128)
- Allow users to add existing skills to projects gradebook
- Allow users to move/delete project skills
- Show previous scores in multiple term section gradebooks
0.2.1 (2012-09-27)
------------------
- Sorted worksheets in third-nav of the gradebook views
- Edit document hierarchy view now sorts by hierarchy order
- Nodes table filter now orders layer checkboxes by hierarchy order
- I can't set a node label through the web (https://launchpad.net/bugs/1049442)
0.2 (2012-09-13)
----------------
- Added CourseNodes sheet to skills importer
- Made Batch Assign Skills view to associate several nodes at once
- Skills Document table views need cyclic relationship check (https://launchpad.net/bugs/1030865)
- Added Skill Sets tab back to skills tertiary
0.1 (2012-08-08)
----------------
Initial release.
Platform: any
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: GNU General Public License (GPL)
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Zope
Classifier: Topic :: Education
schooltool.cando-2.6.2/src/schooltool.cando.egg-info/requires.txt 0000644 0001750 0001750 00000000204 12322040274 026242 0 ustar menesis menesis 0000000 0000000 schooltool >= 2.6
schooltool.gradebook >= 2.6
setuptools
zope.i18n
zope.i18nmessageid
[test]
schooltool.devtools>=0.6
z3c.form>=2.6 schooltool.cando-2.6.2/src/schooltool.cando.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 12322040274 027714 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool.cando.egg-info/namespace_packages.txt 0000644 0001750 0001750 00000000013 12322040274 030173 0 ustar menesis menesis 0000000 0000000 schooltool
schooltool.cando-2.6.2/src/schooltool.cando.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 12270520476 026105 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/ 0000755 0001750 0001750 00000000000 12322040274 021071 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool/__init__.py 0000644 0001750 0001750 00000000070 12270520445 023204 0 ustar menesis menesis 0000000 0000000 __import__('pkg_resources').declare_namespace(__name__)
schooltool.cando-2.6.2/src/schooltool/cando/ 0000755 0001750 0001750 00000000000 12322040274 022155 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool/cando/stesting.py 0000644 0001750 0001750 00000011744 12270520445 024403 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""
Selenium Functional Testing Utilities for skills.
"""
import os
from schooltool.testing.selenium import SeleniumLayer
dir = os.path.abspath(os.path.dirname(__file__))
filename = os.path.join(dir, 'stesting.zcml')
skill_selenium_layer = SeleniumLayer(filename,
__name__,
'skill_selenium_layer')
def registerSeleniumSetup():
try:
import selenium
except ImportError:
return
from schooltool.testing import registry
import schooltool.testing.selenium
def importGlobalSkills(browser, filename):
browser.query.link('School').click()
browser.query.link('Skills').click()
browser.query.link('Import Skill Data').click()
if filename:
browser.query.name('xlsfile').type(filename)
page = browser.query.tag('html')
browser.query.button('Submit').click()
browser.wait(lambda: page.expired)
registry.register('SeleniumHelpers',
lambda: schooltool.testing.selenium.registerBrowserUI(
'skill.import_xls', importGlobalSkills))
def addSkillSet(browser, title, label=None):
browser.query.link('School').click()
browser.query.link('Skills').click()
browser.query.link('Skill Sets').click()
browser.query.link('Skill Set').click()
browser.query.name('form.widgets.title').type(title)
if label is not None:
browser.query.name('form.widgets.label').type(label)
page = browser.query.tag('html')
browser.query.button('Submit').click()
browser.wait(lambda: page.expired)
registry.register('SeleniumHelpers',
lambda: schooltool.testing.selenium.registerBrowserUI(
'skillset.add', addSkillSet))
def addSkill(browser, skillset, title, label=None, required=True,
external_id=None, scoresystem=None):
browser.query.link('School').click()
browser.query.link('Skills').click()
browser.query.link('Skill Sets').click()
browser.query.link(skillset).click()
browser.query.link('Skill').click()
browser.query.name('form.widgets.title').type(title)
if label is not None:
browser.query.name('form.widgets.label').type(label)
if required:
browser.query.id('form-widgets-required-0').click()
else:
browser.query.id('form-widgets-required-1').click()
if external_id is not None:
browser.query.name('form.widgets.external_id').type(external_id)
if scoresystem is not None:
browser.query.name('form.widgets.scoresystem:list').ui.set_value(scoresystem)
else:
browser.query.name('form.widgets.scoresystem:list').ui.set_value('Competency')
page = browser.query.tag('html')
browser.query.button('Submit').click()
browser.wait(lambda: page.expired)
registry.register('SeleniumHelpers',
lambda: schooltool.testing.selenium.registerBrowserUI(
'skill.add', addSkill))
def addLayer(browser, title):
browser.query.link('School').click()
browser.query.link('Skills').click()
browser.query.link('Layers').click()
browser.query.link('Layer').click()
browser.query.name('form.widgets.title').type(title)
page = browser.query.tag('html')
browser.query.button('Submit').click()
browser.wait(lambda: page.expired)
registry.register('SeleniumHelpers',
lambda: schooltool.testing.selenium.registerBrowserUI(
'layer.add', addLayer))
def addNode(browser, title, label=None):
browser.query.link('School').click()
browser.query.link('Skills').click()
browser.query.link('Search').click()
browser.query.link('Node').click()
browser.query.name('form.widgets.title').type(title)
if label is not None:
browser.query.name('form.widgets.label').type(label)
page = browser.query.tag('html')
browser.query.button('Submit').click()
browser.wait(lambda: page.expired)
registry.register('SeleniumHelpers',
lambda: schooltool.testing.selenium.registerBrowserUI(
'node.add', addNode))
registerSeleniumSetup()
del registerSeleniumSetup
schooltool.cando-2.6.2/src/schooltool/cando/model.zcml 0000644 0001750 0001750 00000010020 12270520445 024142 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/project.py 0000644 0001750 0001750 00000031115 12270520445 024203 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""Gradebook projects."""
from decimal import Decimal
from persistent.dict import PersistentDict
from zope.annotation.interfaces import IAnnotations
from zope.interface import implements, implementer
from zope.event import notify
from zope.component import (adapter, adapts, getUtility, getAdapters,
queryAdapter)
from zope.container.contained import containedEvent
from zope.container.interfaces import INameChooser
from zope.i18n import translate
from zope.intid.interfaces import IIntIds
from zope.keyreference.interfaces import IKeyReference
from zope.proxy import sameProxiedObjects
from schooltool.requirement.requirement import Requirement
from schooltool.requirement.scoresystem import UNSCORED
from schooltool.gradebook.activity import Worksheets, Worksheet
from schooltool.gradebook.interfaces import IExternalActivity
from schooltool.gradebook.interfaces import IExternalActivities
from schooltool.cando.interfaces import IProjects, IProject, IProjectsGradebook
from schooltool.cando.interfaces import ICourseProjects, ICourseProject
from schooltool.cando.interfaces import ISectionSkills, ISkillsGradebook
from schooltool.cando.skill import SkillSet
from schooltool.course.interfaces import ISection, ICourse
from schooltool.cando import CanDoMessage as _
SECTION_PROJECTS_KEY = 'schooltool.cando.project.sectionprojects'
COURSE_PROJECTS_KEY = 'schooltool.cando.project.courseprojects'
class Projects(Worksheets):
implements(IProjects)
annotations_current_worksheet_key = 'schooltool.cando.project.currentworksheet'
class Project(SkillSet, Worksheet):
implements(IProject)
class CourseProjects(Requirement):
implements(ICourseProjects)
deployed_projects = None
def __init__(self, *args, **kw):
self.deployed_projects = PersistentDict()
def isDeployed(self, project, section):
if (project.__name__ not in self or
not sameProxiedObjects(project.__parent__, self)):
raise KeyError(project.__name__)
project_hash = hash(IKeyReference(project))
section_hash = hash(IKeyReference(section))
if project_hash not in self.deployed_projects:
return False
if section_hash not in self.deployed_projects[project_hash]:
return False
return True
def markDeployed(self, project, deployed_project):
if (project.__name__ not in self or
not sameProxiedObjects(project.__parent__, self)):
raise KeyError(project.__name__)
project_hash = hash(IKeyReference(project))
section = ISection(deployed_project.__parent__)
section_hash = hash(IKeyReference(section))
if project_hash not in self.deployed_projects:
self.deployed_projects[project_hash] = PersistentDict()
deployed_hash = hash(IKeyReference(deployed_project))
self.deployed_projects[project_hash][section_hash] = deployed_hash
deployed_project.deployed = True
def deploy(self, project, section):
if (project.__name__ not in self or
not sameProxiedObjects(project.__parent__, self)):
raise KeyError(project.__name__)
if self.isDeployed(project, section):
return
section_projects = IProjects(section)
deployed_project = Project(title=project.title,
description=project.description)
chooser = INameChooser(section_projects)
name = chooser.chooseName(project.__name__, deployed_project)
section_projects[name] = deployed_project
for skill in project.values():
new_skill = deployed_project.add(skill)
skill.equivalent.add(new_skill)
self.markDeployed(project, deployed_project)
class CourseProject(SkillSet):
implements(ICourseProject)
@property
def deployed(self):
course_projects = self.__parent__
course = ICourse(course_projects)
for section in course.sections:
if not course_projects.isDeployed(self, section):
return False
return True
@adapter(ICourse)
@implementer(ICourseProjects)
def getCourseProjects(course):
annotations = IAnnotations(course)
try:
return annotations[COURSE_PROJECTS_KEY]
except KeyError:
projects = CourseProjects(_('Course Projects'))
annotations[COURSE_PROJECTS_KEY] = projects
# Sigh, this is not good.
projects, event = containedEvent(projects, course, 'projects')
notify(event)
return projects
# Convention to make adapter introspectable
getCourseProjects.factory = CourseProjects
@adapter(ICourseProjects)
@implementer(ICourse)
def getCourseFromProjects(projects):
annotations = projects.__parent__
course = annotations.__parent__
return course
@adapter(ISection)
@implementer(IProjects)
def getSectionProjects(section):
annotations = IAnnotations(section)
try:
return annotations[SECTION_PROJECTS_KEY]
except KeyError:
projects = Projects(_('Projects'))
annotations[SECTION_PROJECTS_KEY] = projects
# Sigh, this is not good.
projects, event = containedEvent(projects, section, 'projects')
notify(event)
return projects
getSectionProjects.factory = Projects
@adapter(IProjects)
@implementer(ISection)
def getSectionFromProjects(projects):
annotations = projects.__parent__
section = annotations.__parent__
return section
class CanDoExternalActivityProject(object):
implements(IExternalActivity)
adapts(IProject)
def __init__(self, context):
self.project = context
self.gradebook = IProjectsGradebook(context)
self.__parent__ = context
self.source = ""
self.external_activity_id = ""
@property
def description(self):
return self.project.description
def __eq__(self, other):
return IExternalActivity.providedBy(other) and \
self.source == other.source and \
self.external_activity_id == other.external_activity_id
class CanDoExternalActivityProjectTotal(CanDoExternalActivityProject):
@property
def title(self):
msg = _('${project} total points',
mapping={'project': self.project.title})
return translate(msg)
def getGrade(self, student):
numComps = totalPoints = 0
ss = None
for competency in self.project.values():
numComps += 1
ev = self.gradebook.getScore(student, competency)
if ev is None or ev.value == UNSCORED:
continue
value = ev.scoreSystem.getNumericalValue(ev.value)
totalPoints += value
if not ss:
ss = ev.scoreSystem
if numComps:
if not totalPoints:
return Decimal(0)
bestScore = ss.getNumericalValue(ss.getBestScore())
return Decimal(totalPoints) / Decimal(numComps) / bestScore
return None
class CanDoExternalActivityProjectPercentPassed(CanDoExternalActivityProject):
@property
def title(self):
msg = _('${project} percent passed',
mapping={'project': self.project.title})
return translate(msg)
def getGrade(self, student):
numComps = totalPassed = 0
for competency in self.project.values():
numComps += 1
ev = self.gradebook.getScore(student, competency)
if ev is None or ev.value == UNSCORED:
continue
if ev.scoreSystem.isPassingScore(ev.value):
totalPassed += 1
if numComps:
return Decimal(totalPassed) / Decimal(numComps)
return None
class CanDoExternalActivitySection(object):
implements(IExternalActivity)
adapts(ISection)
def __init__(self, context):
self.section = context
self.courses = ', '.join([c.title for c in self.section.courses])
self.__parent__ = context
self.source = ""
self.external_activity_id = ""
@property
def description(self):
return self.section.description
def __eq__(self, other):
return IExternalActivity.providedBy(other) and \
self.source == other.source and \
self.external_activity_id == other.external_activity_id
class CanDoExternalActivitySectionTotal(CanDoExternalActivitySection):
@property
def title(self):
msg = _('${course} total points',
mapping={'course': self.courses})
return translate(msg)
def getGrade(self, student):
numComps = totalPoints = 0
ss = None
for skillset in ISectionSkills(self.section).values():
gradebook = ISkillsGradebook(skillset)
for competency in skillset.values():
numComps += 1
ev = gradebook.getScore(student, competency)
if ev is None or ev.value == UNSCORED:
continue
value = ev.scoreSystem.getNumericalValue(ev.value)
totalPoints += value
if not ss:
ss = ev.scoreSystem
if numComps:
if not totalPoints:
return Decimal(0)
bestScore = ss.getNumericalValue(ss.getBestScore())
return Decimal(totalPoints) / Decimal(numComps) / bestScore
return None
class CanDoExternalActivitySectionPercentPassed(CanDoExternalActivitySection):
@property
def title(self):
msg = _('${course} percent passed',
mapping={'course': self.courses})
return translate(msg)
def getGrade(self, student):
numComps = totalPassed = 0
for skillset in ISectionSkills(self.section).values():
gradebook = ISkillsGradebook(skillset)
for competency in skillset.values():
numComps += 1
ev = gradebook.getScore(student, competency)
if ev is None or ev.value == UNSCORED:
continue
if ev.scoreSystem.isPassingScore(ev.value):
totalPassed += 1
if numComps:
return Decimal(totalPassed) / Decimal(numComps)
return None
class CanDoExternalActivities(object):
implements(IExternalActivities)
title = u"CanDo"
source = "cando.external_activities"
def __init__(self, context):
self.context = context
self.__parent__ = context
def getExternalActivities(self):
result = []
intids = getUtility(IIntIds)
section_projects = IProjects(self.context)
for project in section_projects.values():
for name, activity in getAdapters([project], IExternalActivity):
external_activity = activity
external_activity.source = self.source
external_id = '%s_%s' % (name, intids.getId(project))
external_activity.external_activity_id = external_id
result.append(external_activity)
for name, activity in getAdapters([self.context], IExternalActivity):
external_activity = activity
external_activity.source = self.source
external_id = '%s_%s' % (name, intids.getId(self.context))
external_activity.external_activity_id = external_id
result.append(external_activity)
return result
def getExternalActivity(self, external_activity_id):
parts = external_activity_id.split('_')
if len(parts) != 2:
return None
name, context_intid = parts
try:
context_intid = int(context_intid)
except (ValueError,):
return None
context = getUtility(IIntIds).queryObject(context_intid)
if context is None:
return None
activity = queryAdapter(context, IExternalActivity, name=name)
if activity is None:
return None
activity.source = self.source
activity.external_activity_id = external_activity_id
return activity
schooltool.cando-2.6.2/src/schooltool/cando/iep.py 0000644 0001750 0001750 00000007165 12270520445 023322 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""Student Individualized Education Plan (IEP)"""
from persistent import Persistent
from persistent.dict import PersistentDict
from zope.annotation.interfaces import IAnnotations
from zope.component import adapter, getUtility
from zope.intid.interfaces import IIntIds
from zope.interface import implementer
from schooltool.basicperson.interfaces import IBasicPerson
from schooltool.cando.interfaces import ISectionSkills
from schooltool.cando.interfaces import IStudentIEP
STUDENT_IEP_KEY = 'schooltool.cando.iep'
class StudentIEP(Persistent):
active = False
description = None
def __init__(self):
super(StudentIEP, self).__init__()
self.iep_skills = PersistentDict({})
def getIEPSkills(self, section):
result = {}
int_ids = getUtility(IIntIds)
section_id = int_ids.getId(section)
section_iep_skills = self.iep_skills.get(section_id)
if section_iep_skills is not None:
section_skills = ISectionSkills(section)
for skillset_id, skill_ids in section_iep_skills.items():
skillset = section_skills.get(skillset_id)
if skillset is not None:
result[skillset] = []
for skill_id in skill_ids:
skill = skillset.get(skill_id)
if skill is not None:
result[skillset].append(skill)
return result
def addSkill(self, section, skill):
int_ids = getUtility(IIntIds)
section_id = int_ids.getId(section)
section_skills = ISectionSkills(section)
skillset = skill.__parent__
skillset_id = skillset.__name__
if skillset_id in section_skills:
if section_id not in self.iep_skills:
self.iep_skills[section_id] = {}
section_iep_skills = self.iep_skills.get(section_id)
if skillset_id not in section_iep_skills:
section_iep_skills[skillset_id] = set()
section_iep_skills[skillset_id].add(skill.__name__)
def removeSkill(self, section, skill):
int_ids = getUtility(IIntIds)
section_id = int_ids.getId(section)
section_iep_skills = self.iep_skills.get(section_id)
if section_iep_skills is not None:
skill_id = skill.__name__
skillset = skill.__parent__
skillset_id = skillset.__name__
if skillset_id in section_iep_skills and \
skill_id in section_iep_skills[skillset_id]:
section_iep_skills[skillset_id].remove(skill_id)
@implementer(IStudentIEP)
@adapter(IBasicPerson)
def getStudentIEP(person):
annotations = IAnnotations(person)
try:
return annotations[STUDENT_IEP_KEY]
except KeyError:
iep = StudentIEP()
iep.__parent__ = person
annotations[STUDENT_IEP_KEY] = iep
return iep
schooltool.cando-2.6.2/src/schooltool/cando/gradebook.py 0000644 0001750 0001750 00000025463 12270520445 024503 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""CanDo Gradebook."""
from zope.annotation.interfaces import IAnnotations
from zope.cachedescriptors.property import Lazy
from zope.component import adapts, adapter, queryMultiAdapter
from zope.component import getMultiAdapter
from zope.interface import implements, implementer, implementsOnly
from zope.location.location import LocationProxy
from zope.publisher.interfaces import IPublishTraverse
from zope.security import proxy
from schooltool.app.interfaces import ISchoolToolApplication
from schooltool.basicperson.interfaces import IBasicPerson
from schooltool.course.interfaces import ISection
from schooltool.gradebook.activity import ensureAtLeastOneWorksheet
from schooltool.gradebook.gradebook import Gradebook
from schooltool.gradebook.gradebook import StudentGradebook
from schooltool.gradebook.gradebook import getActivityScore
from schooltool.gradebook.gradebook import CURRENT_SECTION_TAUGHT_KEY
from schooltool.gradebook.gradebook import CURRENT_SECTION_ATTENDED_KEY
from schooltool.requirement.interfaces import IHaveEvaluations
from schooltool.requirement.interfaces import IScore
from schooltool.cando.interfaces import ICanDoGradebook
from schooltool.cando.interfaces import IMySkillsGrades
from schooltool.cando.interfaces import IMyProjectsGrades
from schooltool.cando.interfaces import IProject
from schooltool.cando.interfaces import IProjects
from schooltool.cando.interfaces import IProjectsGradebook
from schooltool.cando.interfaces import ISectionSkills
from schooltool.cando.interfaces import ISkillsGradebook
from schooltool.cando.interfaces import ISectionSkillSet
from schooltool.cando.interfaces import ISkill
from schooltool.cando.interfaces import ICanDoStudentGradebook
from schooltool.cando.project import Project
from schooltool.cando import CanDoMessage as _
def ensureAtLeastOneProject(worksheets):
ensureAtLeastOneWorksheet(worksheets, Project, _('Project1'))
class ProjectsGradebook(Gradebook):
implements(IProjectsGradebook)
adapts(IProject)
# XXX: Merge with Gradebook and GradebookBase
def __init__(self, context):
self.context = context
# To make URL creation happy
self.__parent__ = context
self.section = self.context.__parent__.__parent__
# Establish worksheets and all activities
worksheets = IProjects(self.section)
ensureAtLeastOneProject(worksheets)
self.worksheets = list(worksheets.values())
self.activities = []
for activity in context.values():
self.activities.append(activity)
self.students = list(self.section.members)
self.__name__ = 'gradebook-projects'
def getCurrentWorksheet(self, person):
section = self.section
worksheets = IProjects(section)
current = worksheets.getCurrentWorksheet(person)
return current
def setCurrentWorksheet(self, person, worksheet):
section = self.section
worksheets = IProjects(section)
worksheet = proxy.removeSecurityProxy(worksheet)
worksheets.setCurrentWorksheet(person, worksheet)
def filterEquivalent(self, equivalent):
# select only equivalent skills that belong to this section
return filter(
lambda e: ISection(e.__parent__, None) is self.section,
equivalent)
def evaluate(self, student, activity, score, evaluator=None):
super(ProjectsGradebook, self).evaluate(
student, activity, score, evaluator)
equivalent = self.filterEquivalent(activity.findAllEquivalent())
for skill in equivalent:
worksheet = skill.__parent__
gradebook = ISkillsGradebook(worksheet, None)
if gradebook is not None:
gradebook.evaluate(student, skill, score, evaluator)
def removeEvaluation(self, student, activity, evaluator=None):
super(ProjectsGradebook, self).removeEvaluation(
student, activity, evaluator)
equivalent = self.filterEquivalent(activity.findAllEquivalent())
for skill in equivalent:
worksheet = skill.__parent__
gradebook = ISkillsGradebook(worksheet, None)
if gradebook is not None:
gradebook.removeEvaluation(student, skill, evaluator)
class SkillsGradebook(Gradebook):
implements(ISkillsGradebook)
adapts(ISectionSkillSet)
# XXX: Merge with Gradebook and GradebookBase
def __init__(self, context):
self.context = context
# To make URL creation happy
self.__parent__ = context
self.section = self.context.__parent__.__parent__
# Establish worksheets and all activities
worksheets = ISectionSkills(self.section)
self.worksheets = list(worksheets.values())
self.activities = []
for activity in context.values():
self.activities.append(activity)
self.students = list(self.section.members)
self.__name__ = 'gradebook-skills'
def getCurrentWorksheet(self, person):
section = self.section
worksheets = ISectionSkills(section)
current = worksheets.getCurrentWorksheet(person)
return current
def setCurrentWorksheet(self, person, worksheet):
section = self.section
worksheets = ISectionSkills(section)
worksheet = proxy.removeSecurityProxy(worksheet)
worksheets.setCurrentWorksheet(person, worksheet)
def getScore(self, student, activity):
score = super(SkillsGradebook, self).getScore(student, activity)
if score is not None:
return score
if self.section.previous is not None:
return self.getPreviousScore(student, activity, self.section.previous)
def getPreviousScore(self, student, activity, section):
equivalent = self.findEquivalent(activity, section)
if equivalent is not None:
skill = proxy.removeSecurityProxy(equivalent)
worksheet = skill.__parent__
gradebook = ISkillsGradebook(worksheet, None)
if gradebook is not None:
try:
score = gradebook.getScore(student, skill)
except (ValueError,):
score = None
if score is not None:
return score
def findEquivalent(self, activity, section):
current_skillset_id = activity.__parent__.__name__
skillsets = ISectionSkills(section)
skillset = skillsets.get(current_skillset_id)
if skillset is not None:
return skillset.get(activity.__name__)
class MySkillsGrades(SkillsGradebook):
implementsOnly(IMySkillsGrades)
adapts(ISectionSkillSet)
def __init__(self, context):
super(MySkillsGrades, self).__init__(context)
# To make URL creation happy
self.__name__ = 'mygrades-skills'
class MyProjectsGrades(ProjectsGradebook):
implementsOnly(IMyProjectsGrades)
adapts(IProject)
def __init__(self, context):
super(MyProjectsGrades, self).__init__(context)
# To make URL creation happy
self.__name__ = 'mygrades-projects'
@adapter(IHaveEvaluations, ISkill)
@implementer(IScore)
def getSkillScore(evaluatee, skill):
return getActivityScore(evaluatee, skill)
class ProjectGradebookTraverser(object):
implements(IPublishTraverse)
def __init__(self, context, request):
self.context = context
self.request = request
def publishTraverse(self, request, name):
context = proxy.removeSecurityProxy(self.context)
try:
activity = context[name]
return activity
except KeyError:
if name == 'gradebook':
gb = IProjectsGradebook(context)
gb = LocationProxy(gb, self.context, name)
gb.__setattr__('__parent__', gb.__parent__)
return gb
elif name == 'mygrades':
gb = IMyProjectsGrades(context)
gb = LocationProxy(gb, self.context, name)
gb.__setattr__('__parent__', gb.__parent__)
return gb
else:
return queryMultiAdapter((self.context, request), name=name)
class SkillsGradebookTraverser(object):
implements(IPublishTraverse)
def __init__(self, context, request):
self.context = context
self.request = request
def publishTraverse(self, request, name):
context = proxy.removeSecurityProxy(self.context)
try:
activity = context[name]
return activity
except KeyError:
if name == 'gradebook':
gb = ISkillsGradebook(context)
gb = LocationProxy(gb, self.context, name)
gb.__setattr__('__parent__', gb.__parent__)
return gb
elif name == 'mygrades':
gb = IMySkillsGrades(context)
gb = LocationProxy(gb, self.context, name)
gb.__setattr__('__parent__', gb.__parent__)
return gb
else:
return queryMultiAdapter((self.context, request), name=name)
def getCourseSkillSetSection(worksheet):
return worksheet.__parent__.__parent__
class CanDoStudentGradebook(StudentGradebook):
implements(ICanDoStudentGradebook)
adapts(IBasicPerson, ICanDoGradebook)
@property
def __parent__(self):
return self.gradebook.__parent__
class CanDoStudentGradebookTraverser(object):
implements(IPublishTraverse)
def __init__(self, context, request):
self.context = context
self.request = request
def publishTraverse(self, request, name):
app = ISchoolToolApplication(None)
context = proxy.removeSecurityProxy(self.context)
try:
student = app['persons'][name]
except KeyError:
return queryMultiAdapter((self.context, request), name=name)
try:
gb = getMultiAdapter((student, context), ICanDoStudentGradebook)
except ValueError:
return queryMultiAdapter((self.context, request), name=name)
# location looks like http://host/path/to/gradebook/studentsUsername
gb = LocationProxy(gb, self.context, name)
return gb
schooltool.cando-2.6.2/src/schooltool/cando/project.zcml 0000644 0001750 0001750 00000012203 12270520445 024515 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/__init__.py 0000644 0001750 0001750 00000002016 12270520445 024272 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
from zope.i18nmessageid import MessageFactory
CanDoMessage = MessageFactory("schooltool.cando")
import interfaces
import model
import skill
import project
import stesting
import schooltool.common
schooltool.common.register_lauchpad_project(__package__, 'schooltool.cando')
schooltool.cando-2.6.2/src/schooltool/cando/plugin.zcml 0000644 0001750 0001750 00000000263 12270520445 024350 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/stesting.zcml 0000644 0001750 0001750 00000000572 12270520445 024715 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/security.zcml 0000644 0001750 0001750 00000001226 12270520445 024721 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/skill.py 0000644 0001750 0001750 00000024021 12270520445 023651 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
from decimal import Decimal
from zope.annotation.interfaces import IAnnotations
import zc.catalog.extentcatalog
from zope.catalog.text import TextIndex
from zope.index.text.interfaces import ISearchableText
from zope.interface import implements, implementer
from zope.component import adapter, adapts
from zope.container.btree import BTreeContainer
from zope.container.interfaces import INameChooser
from zope.security.proxy import removeSecurityProxy
from schooltool.app.app import InitBase, StartUpBase
from schooltool.app.catalog import AttributeCatalog
from schooltool.app.interfaces import ISchoolToolApplication
from schooltool.cando import interfaces
from schooltool.relationship import URIObject
from schooltool.relationship import RelationshipSchema, RelationshipProperty
from schooltool.requirement.interfaces import IScoreSystemContainer
from schooltool.requirement.requirement import Requirement
from schooltool.requirement.scoresystem import CustomScoreSystem
from schooltool.requirement.scoresystem import GlobalDiscreteValuesScoreSystem
DEFAULT_SCORESYSTEM_KEY = 'schooltool.cando.defaultscoresystem'
URISkill = URIObject(
'http://schooltool.org/ns/cando/skill',
'Skill',
'A single skill.')
URISkillSet = URIObject(
'http://schooltool.org/ns/cando/skillset',
'Skillset',
'A set of skills.')
URIEquivalent = URIObject(
'http://schooltool.org/ns/cando/skill/equivalent',
'Equivalent',
'All equivalend skills.')
EquivalentSkills = RelationshipSchema(
URIEquivalent,
skill=URISkill,
equivalent=URISkill)
class Skill(Requirement):
implements(interfaces.ISkill)
external_id = u''
label = u''
description = u''
required = False
retired = False
custom_scoresystem = None
equivalent = RelationshipProperty(URIEquivalent, URISkill, URISkill)
def __init__(self, title, required=False, external_id=u'', label=u'',
scoresystem=None):
Requirement.__init__(self, title)
self.required = required
self.external_id = external_id
self.label = label
self.custom_scoresystem = scoresystem
@property
def scoresystem(self):
if self.custom_scoresystem is not None:
return self.custom_scoresystem
return querySkillScoreSystem()
@scoresystem.setter
def scoresystem(self, new_scoresystem):
self.custom_scoresystem = new_scoresystem
def findAllEquivalent(self):
"""Find indirectly equivalent skills."""
visited = set()
result = list()
open = set(self.equivalent)
while open:
skill = open.pop()
# XXX: proxies!
if (skill not in visited and
skill is not self):
visited.add(skill)
result.append(skill)
open.update(set(skill.equivalent).difference(set(visited)))
return result
def copy(self):
return Skill(title=self.title,
required=self.required,
external_id=self.external_id,
label=self.label)
def __repr__(self):
desc = unicode(self.title)
if len(desc) > 40:
desc = desc[:17]+'...'+desc[-20:]
return '' % unicode(desc)
class SkillSetContainer(BTreeContainer):
"""Container of skill sets."""
implements(interfaces.ISkillSetContainer)
class SkillSet(Requirement):
implements(interfaces.ISkillSet)
description = u''
label = u''
retired = False
def __init__(self, title, description=u'', label=u''):
Requirement.__init__(self, title)
self.description = description
self.label = label
def add(self, skill):
skill_copy = skill.copy()
chooser = INameChooser(self)
name = chooser.chooseName(skill.__name__, skill_copy)
self[name] = skill_copy
return skill_copy
class SkillInit(InitBase):
def __call__(self):
self.app['schooltool.cando.skillset'] = SkillSetContainer()
class SkillAppStartup(StartUpBase):
def __call__(self):
if 'schooltool.cando.skillset' not in self.app:
self.app['schooltool.cando.skillset'] = SkillSetContainer()
@implementer(interfaces.ISkillSetContainer)
@adapter(ISchoolToolApplication)
def getSkillSetContainer(app):
return app['schooltool.cando.skillset']
SkillScoreSystem = GlobalDiscreteValuesScoreSystem(
'SkillScoreSystem',
u'Competency', u'Skill Competency Score',
[('4', u'Expert', Decimal(4), Decimal(90)),
('3', u'Competent', Decimal(3), Decimal(70)),
('2', u'Practicing', Decimal(2), Decimal(50)),
('1', u'Beginning', Decimal(1), Decimal(30)),
('0', u'Uninformed', Decimal(0), Decimal(0))],
'4', '3')
class ScoreSystemAppStartup(StartUpBase):
after = ('schooltool.requirement.scoresystem', )
def __call__(self):
ssc = IScoreSystemContainer(self.app)
if SkillScoreSystem.__name__ in ssc:
return
ssc[SkillScoreSystem.__name__] = CustomScoreSystem(
SkillScoreSystem.title, SkillScoreSystem.description,
SkillScoreSystem.scores,
SkillScoreSystem._bestScore, SkillScoreSystem._minPassingScore)
def querySkillScoreSystem():
"""Get default skill score system for evaluations."""
app = ISchoolToolApplication(None)
ssc = IScoreSystemContainer(app)
ss = ssc.get(SkillScoreSystem.__name__, None)
if ss is not None:
return ss
if len(ssc) > 0:
return ssc.values()[0]
return None
def getDefaultSkillScoreSystem(person):
default_ss = querySkillScoreSystem()
if default_ss is None:
return None
default = [default_ss.__name__.encode('punycode')]
if person is None:
return default
ann = IAnnotations(removeSecurityProxy(person))
if DEFAULT_SCORESYSTEM_KEY not in ann:
return default
return ann[DEFAULT_SCORESYSTEM_KEY]
def setDefaultSkillScoreSystem(person, scoresystem):
if person is None:
return
person = removeSecurityProxy(person)
ann = IAnnotations(person)
ann[DEFAULT_SCORESYSTEM_KEY] = scoresystem
def is_global_skillset(index, docid, item):
if (not interfaces.ISkillSet.providedBy(item) or
not interfaces.ISkillSetContainer.providedBy(item.__parent__) or
not ISchoolToolApplication.providedBy(item.__parent__.__parent__)):
return False
return True
def is_global_skill(index, docid, item):
if (not interfaces.ISkill.providedBy(item) or
not interfaces.ISkillSet.providedBy(item.__parent__) or
not interfaces.ISkillSetContainer.providedBy(item.__parent__.__parent__) or
not ISchoolToolApplication.providedBy(item.__parent__.__parent__.__parent__)):
return False
return True
searchable_common_indexes = {
'text_ID': 'getSearchableID',
'text_title': 'getSearchableTitle',
'text_label': 'getSearchableLabel',
}
def setSearchableIndexes(catalog):
catalog['text'] = TextIndex('getSearchableText', ISearchableText, True)
for index_id, method_name in searchable_common_indexes.items():
catalog[index_id] = TextIndex(method_name, ISearchableText, True)
class SkillCatalog(AttributeCatalog):
version = '1.3 - add __name__ to text index'
interface = interfaces.ISkill
attributes = ('title', 'external_id', 'label', 'description',
'required', 'retired')
def createCatalog(self):
return zc.catalog.extentcatalog.Catalog(
zc.catalog.extentcatalog.FilterExtent(is_global_skill))
def setIndexes(self, catalog):
super(SkillCatalog, self).setIndexes(catalog)
setSearchableIndexes(catalog)
getSkillCatalog = SkillCatalog.get
class SearchableTextMixin(object):
def getSearchableID(self):
return self.context.__name__
def getSearchableTitle(self):
return self.context.title
def getSearchableLabel(self):
return self.context.label or ''
class SearchableTextSkill(SearchableTextMixin):
adapts(interfaces.ISkill)
implements(ISearchableText)
def __init__(self, context):
self.context = context
def getSearchableText(self):
result = [
self.context.__name__,
self.context.title,
self.context.external_id or '',
self.context.label or '',
self.context.description or '',
]
return ' '.join(result)
class SkillSetCatalog(AttributeCatalog):
version = '1.3 - add __name__ to text index'
interface = interfaces.ISkillSet
attributes = ('title', 'label', 'description', 'retired')
def createCatalog(self):
return zc.catalog.extentcatalog.Catalog(
zc.catalog.extentcatalog.FilterExtent(is_global_skillset))
def setIndexes(self, catalog):
super(SkillSetCatalog, self).setIndexes(catalog)
setSearchableIndexes(catalog)
getSkillSetCatalog = SkillSetCatalog.get
class SearchableTextSkillSet(SearchableTextMixin):
adapts(interfaces.ISkillSet)
implements(ISearchableText)
def __init__(self, context):
self.context = context
def getSearchableText(self):
result = [
self.context.__name__,
self.context.title,
self.context.label or '',
self.context.description or '',
]
return ' '.join(result)
# + directly equivalent
# + all equivalent
schooltool.cando-2.6.2/src/schooltool/cando/skill.zcml 0000644 0001750 0001750 00000004505 12270520445 024173 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/course.py 0000644 0001750 0001750 00000032303 12270520445 024035 0 ustar menesis menesis 0000000 0000000 #
# SchoolTool - common information systems platform for school administration
# Copyright (c) 2012 Shuttleworth Foundation
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
"""Integration with SchoolTool course"""
from persistent.dict import PersistentDict
import zope.lifecycleevent
from zope.annotation.interfaces import IAnnotations
from zope.event import notify
from zope.interface import implements, implementer
from zope.intid.interfaces import IIntIds
from zope.cachedescriptors.property import Lazy
from zope.component import adapts, adapter, getUtility
from zope.container.contained import containedEvent
from zope.lifecycleevent.interfaces import IObjectAddedEvent
from zope.lifecycleevent.interfaces import IObjectRemovedEvent
from zope.lifecycleevent.interfaces import IObjectModifiedEvent
from zope.lifecycleevent import ObjectModifiedEvent
from zope.proxy.decorator import SpecificationDecoratorBase
from zope.proxy import getProxiedObject
from zope.security.proxy import removeSecurityProxy
from schooltool.app.interfaces import ISchoolToolApplication
from schooltool.app.relationships import CourseSections
from schooltool.app.relationships import URICourseSections
from schooltool.app.relationships import URISectionOfCourse, URICourse
from schooltool.cando.interfaces import ICourseSkills
from schooltool.cando.interfaces import ICourseSkillSet, ICourseSkill
from schooltool.cando.interfaces import ISectionSkills, ISectionSkillSet
from schooltool.cando.interfaces import ISkillSetContainer, ISkillSet, ISkill
from schooltool.cando.skill import Skill, is_global_skillset
from schooltool.course.interfaces import ISection, ICourse
from schooltool.course.interfaces import ICourseContainer
from schooltool.gradebook.activity import Worksheets, GenericWorksheet
from schooltool.requirement.requirement import Requirement
from schooltool.schoolyear.interfaces import ISchoolYearContainer
from schooltool.schoolyear.subscriber import ObjectEventAdapterSubscriber
from schooltool.cando import CanDoMessage as _
COURSE_SKILLS_KEY = 'schooltool.cando.project.courseskills'
SECTION_SKILLS_KEY = 'schooltool.cando.project.sectionskills'
class CourseSkills(Requirement):
implements(ICourseSkills)
class ReadOnlyContainer(KeyError):
pass
class SectionSkillSet(GenericWorksheet):
implements(ISectionSkillSet)
skillset = None
def __init__(self, skillset):
self.skillset = skillset
super(SectionSkillSet, self).__init__(skillset.title)
@property
def deployed(self):
return False
@property
def title(self):
return self.skillset.title
@title.setter
def title(self, value):
pass
@property
def description(self):
course_skillset = self.skillset
return course_skillset.skillset.description
@property
def label(self):
course_skillset = self.skillset
return course_skillset.skillset.label
def all_keys(self):
return super(SectionSkillSet, self).keys()
def keys(self):
return [key for key in self.all_keys()
if not self[key].retired]
def __contains__(self, key):
return key in self.all_keys()
class CourseSkillSet(GenericWorksheet):
implements(ICourseSkillSet)
required = None
retired = None
def __init__(self, skillset):
super(CourseSkillSet, self).__init__(skillset.title)
self.required = PersistentDict()
self.retired = PersistentDict()
@Lazy
def skillset(self):
if self.__name__ is None:
return None
app = ISchoolToolApplication(None)
ssc = ISkillSetContainer(app)
return ssc.get(self.__name__)
def all_keys(self):
return list(self.skillset.keys())
def keys(self):
skillset = self.skillset
return [key for key in skillset.keys()
if not self.retired.get(key)]
def __getitem__(self, key):
skillset = self.skillset
skill = skillset[key]
cs = CourseSkill(skill)
cs.__parent__ = self
return cs
def __setitem__(self, key, newobject):
raise ReadOnlyContainer(key)
def __delitem__(self, key):
raise ReadOnlyContainer(key)
class CourseSkill(SpecificationDecoratorBase):
"""A skill proxy that allows overriding of required/retired attributes."""
implements(ICourseSkill)
__slots__ = ('__parent__', )
@property
def required(self):
if self.__name__ not in self.__parent__.required:
unproxied = getProxiedObject(self)
return unproxied.required
return self.__parent__.required[self.__name__]
@required.setter
def required(self, value):
self.__parent__.required[self.__name__] = value
@property
def retired(self):
if self.__name__ not in self.__parent__.retired:
unproxied = getProxiedObject(self)
return unproxied.retired
return self.__parent__.retired[self.__name__]
@retired.setter
def retired(self, value):
self.__parent__.retired[self.__name__] = value
@adapter(ICourse)
@implementer(ICourseSkills)
def getCourseSkills(course):
annotations = IAnnotations(course)
try:
return annotations[COURSE_SKILLS_KEY]
except KeyError:
skills = CourseSkills(_('Course Skills'))
annotations[COURSE_SKILLS_KEY] = skills
# Sigh, this is not good.
skills, event = containedEvent(skills, course, 'skills')
notify(event)
return skills
getCourseSkills.factory = CourseSkills
@adapter(ICourseSkills)
@implementer(ICourse)
def getCourseSkillsCourse(skills):
return skills.__parent__
class SectionSkills(Worksheets):
implements(ISectionSkills)
annotations_current_worksheet_key = 'schooltool.cando.project.sectionskills'
class SectionSkill(Skill):
section_intid = None
source_skillset_name = None
source_skill_name = None
@property
def section(self):
if self.section_intid is None:
return None
int_ids = getUtility(IIntIds)
section = int_ids.queryObject(self.section_intid)
return section
@adapter(ISection)
@implementer(ISectionSkills)
def getSectionSkills(section):
annotations = IAnnotations(section)
try:
return annotations[SECTION_SKILLS_KEY]
except KeyError:
skills = SectionSkills(_('Section Skills'))
annotations[SECTION_SKILLS_KEY] = skills
# Sigh, this is not good.
skills, event = containedEvent(skills, section, 'skills')
notify(event)
return skills
getSectionSkills.factory = SectionSkills
class CourseWorksheetEventSubscriber(ObjectEventAdapterSubscriber):
@property
def sections(self):
skillset = self.object
course = removeSecurityProxy(ICourse(skillset.__parent__))
sections = list(CourseSections.query(course=course))
return sections
class CourseWorksheetRemoved(CourseWorksheetEventSubscriber):
adapts(IObjectRemovedEvent, ICourseSkillSet)
def __call__(self):
skillset = self.object
for section in self.sections:
worksheets = ISectionSkills(section)
if self.object.__name__ in worksheets:
del worksheets[skillset.__name__]
class ICustomObjectModifiedEvent(IObjectModifiedEvent):
pass
class CustomObjectModifiedEvent(ObjectModifiedEvent):
implements(ICustomObjectModifiedEvent)
class GlobalSkillSetUpdateMixin(object):
def yearsToUpdate(self):
app = ISchoolToolApplication(None)
syc = ISchoolYearContainer(app)
active = syc.getActiveSchoolYear()
if active is None:
return list(syc.values())
idx = removeSecurityProxy(syc.sorted_schoolyears).index(removeSecurityProxy(active))
years = syc.sorted_schoolyears[idx:]
return years
def updateSkillSet(self, skillset):
years = self.yearsToUpdate()
for year in years:
courses = ICourseContainer(year)
for course in courses.values():
annotations = IAnnotations(course)
if COURSE_SKILLS_KEY not in annotations:
continue
course_skills = annotations[COURSE_SKILLS_KEY]
for course_skillset in course_skills.values():
if course_skillset.__name__ == skillset.__name__:
notify(CustomObjectModifiedEvent(course_skillset))
class GlobalSkillSetModified(ObjectEventAdapterSubscriber,
GlobalSkillSetUpdateMixin):
adapts(IObjectModifiedEvent, ISkillSet)
def __call__(self):
skillset = self.object
if not is_global_skillset(None, None, skillset):
return
self.updateSkillSet(skillset)
if skillset.retired:
self.retireSkills(skillset)
def retireSkills(self, skillset):
for skill_id in skillset:
skill = skillset[skill_id]
if not skill.retired:
skill.retired = True
zope.lifecycleevent.modified(skill)
class GlobalSkillModified(ObjectEventAdapterSubscriber,
GlobalSkillSetUpdateMixin):
adapts(IObjectModifiedEvent, ISkill)
def __call__(self):
skillset = self.object.__parent__
if not is_global_skillset(None, None, skillset):
return
self.updateSkillSet(skillset)
def updateCourseSkillSet(skillset, section, update_all_attrs=True):
attrs = ('external_id', 'label', 'description', 'title')
if update_all_attrs:
attrs += ('required', 'retired', 'scoresystem')
int_ids = getUtility(IIntIds)
worksheets = ISectionSkills(section)
section_intid = int_ids.getId(section)
unproxied_skillset = removeSecurityProxy(skillset)
if skillset.__name__ not in worksheets:
worksheet = worksheets[skillset.__name__] = SectionSkillSet(unproxied_skillset)
else:
worksheet = worksheets[skillset.__name__]
delete_skills = list(worksheet.all_keys())
for skill_name in skillset.all_keys():
skill = skillset[skill_name]
if skill_name not in worksheet.all_keys():
target_skill = worksheet[skill_name] = SectionSkill(skill.title)
target_skill.equivalent.add(removeSecurityProxy(skill))
else:
if skill_name in delete_skills:
delete_skills.remove(skill_name)
target_skill = worksheet[skill_name]
for attr in attrs:
val = getattr(skill, attr, None)
if getattr(target_skill, attr, None) != val:
setattr(target_skill, attr, val)
if target_skill.section_intid != section_intid:
target_skill.section_intid = section_intid
if target_skill.source_skill_name != skill.__name__:
target_skill.source_skill_name = skill.__name__
if target_skill.source_skillset_name != skill.__parent__.__name__:
target_skill.source_skillset_name = skill.__parent__.__name__
available = worksheet.all_keys()
for skill_name in delete_skills:
if skill_name in available:
del worksheet[skill_name]
class CourseSkillSetModified(CourseWorksheetEventSubscriber):
adapts(IObjectModifiedEvent, ICourseSkillSet)
def __call__(self):
skillset = removeSecurityProxy(self.object)
skillset.title = skillset.skillset.title
for section in self.sections:
updateCourseSkillSet(skillset, section)
class CustomCourseSkillSetModified(CourseWorksheetEventSubscriber):
adapts(ICustomObjectModifiedEvent, ICourseSkillSet)
def __call__(self):
skillset = removeSecurityProxy(self.object)
skillset.title = skillset.skillset.title
for section in self.sections:
updateCourseSkillSet(skillset, section, update_all_attrs=False)
class CourseWorksheetAdded(CourseSkillSetModified):
adapts(IObjectAddedEvent, ICourseSkillSet)
class DeploySkillsToNewSection(ObjectEventAdapterSubscriber):
adapts(IObjectAddedEvent, ISection)
def __call__(self):
section = self.object
for course in section.courses:
courseskills = ICourseSkills(course)
for skillset in courseskills.values():
updateCourseSkillSet(skillset, section)
def updateSectionSkillsOnCourseChange(event):
if event.rel_type != URICourseSections:
return
section = event[URISectionOfCourse]
course = event[URICourse]
courseskills = ICourseSkills(course)
for skillset in courseskills.values():
updateCourseSkillSet(skillset, section)
# XXX: maybe course-skillset relationship views
# XXX: helper: linking of all node skillsets to course
# XXX: helper: copying (with resetting required=False) of skillsets
# (and linking to course)
schooltool.cando-2.6.2/src/schooltool/cando/configure.zcml 0000644 0001750 0001750 00000001162 12270520445 025032 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/course.zcml 0000644 0001750 0001750 00000005722 12270520445 024357 0 ustar menesis menesis 0000000 0000000
schooltool.cando-2.6.2/src/schooltool/cando/locales/ 0000755 0001750 0001750 00000000000 12322040274 023577 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool/cando/locales/es_SV/ 0000755 0001750 0001750 00000000000 12322040274 024616 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool/cando/locales/es_SV/LC_MESSAGES/ 0000755 0001750 0001750 00000000000 12322040274 026403 5 ustar menesis menesis 0000000 0000000 schooltool.cando-2.6.2/src/schooltool/cando/locales/es_SV/LC_MESSAGES/schooltool.cando.mo 0000644 0001750 0001750 00000013105 12322040274 032210 0 ustar menesis menesis 0000000 0000000 Þ• a $ ƒ , 8 9
N \ v ˆ ” ¡ ® ¸ Á ×
è ö + 1 A H [ d p Ÿ " ¹ ! Ü þ
&
+
9
N
k
€
Œ
—
§
³
À
Å
Ì
Ï
ï
/ 6 G X d
n | “ © ® ´ Ä Ì Ô ä
í û
)
0 > + F r {
™ ¤ « »
Ì Ú â é î ô
ù
'
1
<
Q
V
À Z
4 &