TODO: License for this work?
-Notes on component licenses.
+Notes on component licenses:
JQuery
* Copyright (c) 2008 John Resig (jquery.com)
* Copyright (c) 2007 Christian Bach
* Examples and docs at: http://tablesorter.com
* Dual licensed under the MIT and GPL licenses:
+
+Levenshtein Distance implementation by Poromenos, http://www.poromenos.org/node/87.
+Licensed under BSD.
+
+marctools.py:
+ Public Domain 2007 public.resource.org
+ Author: Joel Hardi <joel@hardi.org>
+
+----------------------------------------------------------------------
+SIP support:
+
+Some code borrowed from and/or inspired by the OpenNCIP project.
+
+# Copyright (C) 2006-2008 Georgia Public Library Service
+#
+# Author: David J. Fiander
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+----------------------------------------------------------------------
State of the application
------------------------------
-Extremely primitive! Just working out some user authentication tidbits
-at the moment.
+Coming along nicely, thank you! With a bit of patience, you ought to
+be able to get a basic Syrup system running in no time. Integrating it
+with your backend library and other systems will take longer, of
+course.
-Required Python components
+Required components
------------------------------
+Most likely you will need a Unix-like system: Linux, BSD, or OS X
+ought all to work. Most development and testing is being done on
+Linux. No testing on Windows has been done.
+
You need Python. Probably Python 2.5, I haven't tested with other
versions. You also need sqlite3 or another Django-compatible
database. Sqlite3 is recommended for kicking the tires, PostgreSQL for
production.
-Third-party dependencies:
-
- sudo easy_install Django Genshi Babel BabelDjango pycrypto
-
-Optionally, you can also install:
+Third-party Python dependencies:
- sudo easy_install ply PyZ3950
+ sudo easy_install Django Genshi Babel BabelDjango pexpect
-...though these are just for some Z39.50 code we are testing and
-aren't part of the Syrup Experience yet.
+(You'll need 'setuptools' in order to have 'easy_install'.)
Graham has the following versions installed. Not saying you need these
exact ones, just that they are known to work.
Django-1.0.1_final-py2.5
Babel-0.9.4-py2.5
BabelDjango-0.2.2-py2.5
- Genshi-0.5.1-py2.5-linux-i686
- pycrypto-2.0.1-py2.5-linux-i686
- PyZ3950-2.04-py2.5-linux-i686
- ply-3.1-py2.5
+ Genshi-0.5.1-py2.5
+ pexpect-2.4-py2.5
+
+You will need 'yaz-client' for the Z39.50 stuff. On Ubuntu, this works:
+
+ sudo apt-get install yaz libyaz3
Getting this thing to run
* During syncdb, create yourself a superuser account.
-* ./pybabel-extract
+* ./pybabel-extract (currently, this is optional)
* ./manage.py runserver
-* visit http://localhost:8000/syrup/ and log in.
+* visit http://localhost:8000/ and log in.
* create at least one Term and one Department under Admin Options.
babel.cfg -- Babel (i18n) configuration file
The rest is straightforward Django stuff.
+
+
+Customization
+------------------------------
+
+The 'custom' directory contains (or should contain!) all of the bits
+that you really need to customize for your institution. More
+documentation is needed here, but the source code is mostly
+well-documented.
\ No newline at end of file
IMPORTANT:
-* regoranize views.py and other stuff.
-
* set up a proper issue-tracker?
* CSS fixes for Internet Explorer. It looks crappy in IE.
* Send me email when my sites change?
+* "create course site" (not "add course")
+
MAYBE:
* Generating barcodes in emails, printable screens? (3 of 9 enough?)
* add a hook for a MARC-record-to-maybe-cover-image-URL function
-apt-get install libyaz3 yaz
-easy_install pexpect
-
-create course site (not add course)
-capitalizing labels...
--- /dev/null
+# -*- mode: text; mode: auto-fill; -*-
+
+
+Fleshing out the course model
+--------------------------------------------------
+
+These are just some stream-of-thought notes; don't take them too
+seriously yet.
+
+
+
+We should capitalize on external data sources for course and
+registration information. At the same time, it must be possible to
+use Syrup without an external source, or in a mixed mode (where some
+courses are defined externally and others are ad-hoc).
+
+There will be local variations in the quality of course information.
+Possibly some can provide lists of known courses, but not registration
+information; others will know students enrolled but may not know
+instructors (or vice versa).
+
+So, in fact we have a number of granular external sources, and Syrup
+should operate with any combination of them.
+
+* list of terms (but allowing ad-hoc terms);
+
+* list of course codes and titles (not time- or term-related);
+
+* list of offerings (course-code offered in term);
+
+* list of sections (same course offered several times in one term,
+ and/or broken up into multiple subgroups. Some reserve courses may
+ aggregate some sections, excluding others). Sections are ultimately
+ the join-points between instructors and students, so we must handle
+ them well;
+
+* cross-listings (equivalent course-codes);
+
+* people (username/identifier, given, surname, email)
+
+* instructor and student relationships (fred teaches FRE233/2009W/01;
+ bill takes ESP125/2009W/03).
+
+
+Rolls-Royce Scenario
+--------------------------------------------------
+
+Shelley Smith wants to set up a reserves-site for the course she's
+teaching next term. She logs into reserves, clicks on My Courses, and
+clicks Add a New Course Site. The form asks her to pick a term (the
+current term is the default, all future terms are listed in a
+drop-down), and to pick a course. The system suggests the courses she
+is currently teaching; but this is for a future term, and she's not
+the instructor of record yet, so she picks the code and title from a
+drop-down list.
+
+She doesn't specify any sections, since she won't know that for a few
+months yet. The site remains unavailable to students until she does.
+
+Later, she clicks on Invite Students. It asks her to pick the
+course-sections she's teaching from a list. It knows her course is
+cross-listed; the cross-list sections also appear on the list.
+
+Once the sections are selected, and she presses Continue, the students
+are granted access.
+
+ Variation: staff-assistance
+ --------------------------------------------------
+
+ Shelley contacts Ed at the Reserves desk, and tells him she wants to
+ put some items on reserve. She's teaching MAC-100, Intro to Macrame,
+ section 2, in the upcoming term.
+
+ Ed clicks on Assist, and finds Shelley's in the people-list, and
+ selects her. He clicks on Shelley's Courses, then Add New Course,
+ and enters the term and picks MAC-100 from the list. He knows the
+ section so is able to add that right away. The system alerts him to
+ the cross-listed section, and he adds that too.
+
+ The site won't be ready for students until he (or Shelley) activates
+ the site later on.
+
+ Shelley gets an email letting her know the site is ready for
+ content.
+
+ Data sources
+ --------------------------------------------------
+
+ Shelley and Ed logged in against campus LDAP.
+
+ Shelley's current courses and
+
+
+
+Another take
+------------------------------------------------------------
+
+Shelley can set up the course well in advance, with a trivial working
+title, e.g. "Macrame". It's one of Shelley's courses, but no one else
+has access, and it's not associated with any term, etc.
+
+ Instructor: course-add
+ Library-Staff: course-add
+
+Later, when Shelley is ready to open her reserves to her students, she
+opens the site and hits Invite. What appears is a list of the course
+sections she is teaching:
+
+ MAC-100 section 02 -- Introduction to Macrame (58 members)
+ MAC-301 section 01 -- Macrame Advanced Studio (2 members)
+ LAB-203 section 01 -- Macrame in Labour Studies (8 members)
+
+She checkmarks the first and last section, and presses Invite.
+Automatically, her site is available to her students, but it also gets
+a proper title and course number: she is asked to pick either MAC-100
+or LAB-203 as the primary identifier for the site; the other becomes
+an alias.
+
+Later calls Ed -- she's talked with the instructor of Textiles 101,
+and they've agreed to share Shelley's reserves list with the Textiles
+class. She cannot add an arbitrary section to the course site. So Ed
+opens the site; clicks on Invite; clicks Arbitrary Section; and
+specifies the term, course code, and section of the Textiles class.
+
+ Instructor: course-section-invite
+ Library-Staff: course-section-invite-arbitrary
+
+A key point here is that the formal course numbers may not be
+selectable until late in the game; until just before the course, a
+working title may be all that you have. That's fine. Choosing specific
+course sections can be deferred until the registration info is
+available.
+
+
+What about the case where there is no registration data? How do you
+make a site available to an unknown audience?
+
+Have controls for "publishing" a site, that is, making it available to
+unknown users. A few options:
+
+ * Anyone at all can view the site, even anonymously
+
+ * Any logged-in user can view the site
+
+ * The instructor provides an access key out-of-band. The access key
+ auto-invites you into the site. This isn't so bad really.
+
+ * Any logged-in user can request access; the instructor has to grant
+ access. This way lies madness.
+
+Scrapping the madness-path, we're left with a reasonable set of
+options: Anonymous, Authenticated, AccessKey, Restricted (to members
+of the registered list), or NoAccess (for archived sites, etc.). None
+of this applies to instructors and their proxies, just to visitors.
+
+ Instructor: course-change-access
+ Library-Staff: course-change-access-extended
+
+ The extended permissions could let the librarian decide if certain
+ types of materials in the site should be inaccessible to Anonymous
+ users. Or maybe we should just scrap Anonymous access altogether.
+++ /dev/null
-[{"pk": 22, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 8}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_message", "name": "Can add message", "content_type": 4}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_message", "name": "Can change message", "content_type": 4}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_message", "name": "Can delete message", "content_type": 4}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 13, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 5}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 6}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 7}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_course", "name": "Can add course", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_department", "name": "Can add department", "content_type": 13}}, {"pk": 49, "model": "auth.permission", "fields": {"codename": "add_item", "name": "Can add item", "content_type": 17}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_libraryunit", "name": "Can add library unit", "content_type": 10}}, {"pk": 43, "model": "auth.permission", "fields": {"codename": "add_member", "name": "Can add member", "content_type": 15}}, {"pk": 46, "model": "auth.permission", "fields": {"codename": "add_newsitem", "name": "Can add news item", "content_type": 16}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_servicedesk", "name": "Can add service desk", "content_type": 11}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_term", "name": "Can add term", "content_type": 12}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_userprofile", "name": "Can add user profile", "content_type": 9}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_course", "name": "Can change course", "content_type": 14}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_department", "name": "Can change department", "content_type": 13}}, {"pk": 50, "model": "auth.permission", "fields": {"codename": "change_item", "name": "Can change item", "content_type": 17}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_libraryunit", "name": "Can change library unit", "content_type": 10}}, {"pk": 44, "model": "auth.permission", "fields": {"codename": "change_member", "name": "Can change member", "content_type": 15}}, {"pk": 47, "model": "auth.permission", "fields": {"codename": "change_newsitem", "name": "Can change news item", "content_type": 16}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_servicedesk", "name": "Can change service desk", "content_type": 11}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_term", "name": "Can change term", "content_type": 12}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_userprofile", "name": "Can change user profile", "content_type": 9}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_course", "name": "Can delete course", "content_type": 14}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_department", "name": "Can delete department", "content_type": 13}}, {"pk": 51, "model": "auth.permission", "fields": {"codename": "delete_item", "name": "Can delete item", "content_type": 17}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_libraryunit", "name": "Can delete library unit", "content_type": 10}}, {"pk": 45, "model": "auth.permission", "fields": {"codename": "delete_member", "name": "Can delete member", "content_type": 15}}, {"pk": 48, "model": "auth.permission", "fields": {"codename": "delete_newsitem", "name": "Can delete news item", "content_type": 16}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_servicedesk", "name": "Can delete service desk", "content_type": 11}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_term", "name": "Can delete term", "content_type": 12}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_userprofile", "name": "Can delete user profile", "content_type": 9}}, {"pk": 1, "model": "auth.user", "fields": {"username": "test", "first_name": "", "last_name": "", "is_active": true, "is_superuser": true, "is_staff": true, "last_login": "2009-01-02 16:43:19", "groups": [], "user_permissions": [], "password": "sha1$229bd$8aaf67f54e89b7b08cb225ffda299cb0090fb9eb", "email": "test@test.org", "date_joined": "2008-11-20 23:34:03"}}, {"pk": 2, "model": "auth.user", "fields": {"username": "ping", "first_name": "", "last_name": "", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-11-24 13:45:34", "groups": [], "user_permissions": [], "password": "sha1$70d72$e3adfe7fe780b6c220c68e0ec877070ebfa13ab1", "email": "", "date_joined": "2008-11-24 13:45:34"}}, {"pk": 3, "model": "auth.user", "fields": {"username": "billy", "first_name": "billy", "last_name": "test", "is_active": true, "is_superuser": false, "is_staff": true, "last_login": "2008-11-24 15:29:19", "groups": [], "user_permissions": [22, 23, 24, 4, 10, 1, 7, 5, 11, 2, 8, 6, 12, 3, 9, 13, 14, 15, 16, 17, 18, 19, 20, 21, 40, 37, 28, 43, 46, 31, 34, 25, 41, 38, 29, 44, 47, 32, 35, 26, 42, 39, 30, 45, 48, 33, 36, 27], "password": "sha1$258bc$1a76dd9484e36bbbb2fa3ad0df260d21b122f0c9", "email": "billy@test.org", "date_joined": "2008-11-24 15:04:04"}}, {"pk": 4, "model": "auth.user", "fields": {"username": "test1", "first_name": "test1", "last_name": "test 1", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:28:54", "groups": [], "user_permissions": [], "password": "sha1$db545$c2aee0a47444adb26b32ac7560df6b816774003a", "email": "test1@test.org", "date_joined": "2008-12-16 13:28:54"}}, {"pk": 5, "model": "auth.user", "fields": {"username": "test2", "first_name": "test2", "last_name": "test 2", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:05", "groups": [], "user_permissions": [], "password": "sha1$c3b1e$c1fd1a170123015ee8c6bcbb5b435f4ca1495853", "email": "test2@test.org", "date_joined": "2008-12-16 13:29:05"}}, {"pk": 6, "model": "auth.user", "fields": {"username": "test3", "first_name": "test3", "last_name": "test 3", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:13", "groups": [], "user_permissions": [], "password": "sha1$c0e67$11550d7a8ea1d0d2bfea423c35e3dd571011bbd6", "email": "test3@test.org", "date_joined": "2008-12-16 13:29:13"}}, {"pk": 7, "model": "auth.user", "fields": {"username": "test4", "first_name": "test4", "last_name": "test 4", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:20", "groups": [], "user_permissions": [], "password": "sha1$f24b6$2c789995468baa40625f026fbca9c640c6cc0145", "email": "test4@test.org", "date_joined": "2008-12-16 13:29:20"}}, {"pk": 8, "model": "auth.user", "fields": {"username": "test5", "first_name": "test5", "last_name": "test 5", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:26", "groups": [], "user_permissions": [], "password": "sha1$0acba$76ef04eed7dded54f8513a39aa28428244e9f588", "email": "test5@test.org", "date_joined": "2008-12-16 13:29:26"}}, {"pk": 9, "model": "auth.user", "fields": {"username": "test6", "first_name": "test6", "last_name": "test 6", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:33", "groups": [], "user_permissions": [], "password": "sha1$79803$c5a07c8d79872960e75ff573b40e88bf17cf8a7f", "email": "test6@test.org", "date_joined": "2008-12-16 13:29:33"}}, {"pk": 10, "model": "auth.user", "fields": {"username": "test7", "first_name": "test7", "last_name": "test 7", "is_active": true, "is_superuser": false, "is_staff": false, "last_login": "2008-12-16 13:29:41", "groups": [], "user_permissions": [], "password": "sha1$ee081$55d45b502aeb7427269e4b43162406996a938341", "email": "test7@test.org", "date_joined": "2008-12-16 13:29:41"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "course", "name": "course", "app_label": "syrup"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "department", "name": "department", "app_label": "syrup"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 17, "model": "contenttypes.contenttype", "fields": {"model": "item", "name": "item", "app_label": "syrup"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "libraryunit", "name": "library unit", "app_label": "syrup"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 15, "model": "contenttypes.contenttype", "fields": {"model": "member", "name": "member", "app_label": "syrup"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "message", "name": "message", "app_label": "auth"}}, {"pk": 16, "model": "contenttypes.contenttype", "fields": {"model": "newsitem", "name": "news item", "app_label": "syrup"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "servicedesk", "name": "service desk", "app_label": "syrup"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "term", "name": "term", "app_label": "syrup"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "userprofile", "name": "user profile", "app_label": "syrup"}}, {"pk": "e7ecfa18455e44498eb62989675f3ac4", "model": "sessions.session", "fields": {"expire_date": "2008-12-04 23:38:16", "session_data": "gAJ9cQEoVRJfYXV0aF91c2VyX2JhY2tlbmRxAlUpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5k\ncy5Nb2RlbEJhY2tlbmRxA1UNX2F1dGhfdXNlcl9pZHEESwF1LjM2M2RiYTBjN2Y3NmEzMjFmN2Mw\nMGY3NGIwMzQxYzRj\n"}}, {"pk": "aa1ed775e368f86a56fb712d0de9eff8", "model": "sessions.session", "fields": {"expire_date": "2008-12-10 20:27:04", "session_data": "gAJ9cQEoVRJfYXV0aF91c2VyX2JhY2tlbmRxAlUpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5k\ncy5Nb2RlbEJhY2tlbmRxA1UNX2F1dGhfdXNlcl9pZHEESwF1LjM2M2RiYTBjN2Y3NmEzMjFmN2Mw\nMGY3NGIwMzQxYzRj\n"}}, {"pk": "a0a9af88244bb22012652c53131724b2", "model": "sessions.session", "fields": {"expire_date": "2008-12-22 11:45:23", "session_data": "gAJ9cQEoVRJfYXV0aF91c2VyX2JhY2tlbmRxAlUpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5k\ncy5Nb2RlbEJhY2tlbmRxA1UNX2F1dGhfdXNlcl9pZHEESwF1LjM2M2RiYTBjN2Y3NmEzMjFmN2Mw\nMGY3NGIwMzQxYzRj\n"}}, {"pk": "6c4c671475d3b1df141df53bc0b4d68e", "model": "sessions.session", "fields": {"expire_date": "2009-01-16 16:43:19", "session_data": "gAJ9cQEoVRJfYXV0aF91c2VyX2JhY2tlbmRxAlUpZGphbmdvLmNvbnRyaWIuYXV0aC5iYWNrZW5k\ncy5Nb2RlbEJhY2tlbmRxA1UNX2F1dGhfdXNlcl9pZHEESwF1LjM2M2RiYTBjN2Y3NmEzMjFmN2Mw\nMGY3NGIwMzQxYzRj\n"}}, {"pk": 1, "model": "sites.site", "fields": {"domain": "example.com", "name": "example.com"}}, {"pk": 45, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:54:36", "object_repr": "test7--INSTR--1020", "object_id": "8", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 44, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:54:24", "object_repr": "test6--INSTR--1020", "object_id": "7", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 43, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:54:13", "object_repr": "test5--INSTR--1020", "object_id": "6", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 42, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:54:01", "object_repr": "test4--INSTR--1020", "object_id": "5", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 41, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:53:44", "object_repr": "test2--INSTR--1020", "object_id": "4", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 40, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:53:17", "object_repr": "test1", "object_id": "4", "change_message": "Changed last_name.", "user": 1, "content_type": 3}}, {"pk": 39, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:52:17", "object_repr": "test3--INSTR--1020", "object_id": "3", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 38, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:45:12", "object_repr": "test1--INSTR--1020", "object_id": "2", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 37, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:40:26", "object_repr": "test1", "object_id": "4", "change_message": "Changed is_staff.", "user": 1, "content_type": 3}}, {"pk": 36, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:39:20", "object_repr": "test1", "object_id": "4", "change_message": "Changed is_staff.", "user": 1, "content_type": 3}}, {"pk": 35, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:36:32", "object_repr": "test1", "object_id": "4", "change_message": "Changed last_name.", "user": 1, "content_type": 3}}, {"pk": 34, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:34:18", "object_repr": "UserProfile(test7)", "object_id": "8", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 33, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:34:07", "object_repr": "UserProfile(test6)", "object_id": "7", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 32, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:33:56", "object_repr": "UserProfile(test5)", "object_id": "6", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 31, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:33:44", "object_repr": "UserProfile(test4)", "object_id": "5", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 30, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:33:33", "object_repr": "UserProfile(test3)", "object_id": "4", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 29, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:33:22", "object_repr": "UserProfile(test2)", "object_id": "3", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 28, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:33:11", "object_repr": "UserProfile(test1)", "object_id": "2", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 27, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:32:47", "object_repr": "test7", "object_id": "10", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 26, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:32:31", "object_repr": "test6", "object_id": "9", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 25, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:32:10", "object_repr": "test5", "object_id": "8", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 24, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:31:55", "object_repr": "test4", "object_id": "7", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 23, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:31:39", "object_repr": "test3", "object_id": "6", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 22, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:31:19", "object_repr": "test2", "object_id": "5", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 21, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-16 13:31:01", "object_repr": "test1", "object_id": "4", "change_message": "Changed first_name, last_name and email.", "user": 1, "content_type": 3}}, {"pk": 20, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:41", "object_repr": "test7", "object_id": "10", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 19, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:33", "object_repr": "test6", "object_id": "9", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 18, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:26", "object_repr": "test5", "object_id": "8", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 17, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:20", "object_repr": "test4", "object_id": "7", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 16, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:13", "object_repr": "test3", "object_id": "6", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 15, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:29:05", "object_repr": "test2", "object_id": "5", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 14, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-16 13:28:54", "object_repr": "test1", "object_id": "4", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 13, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-12-08 11:21:06", "object_repr": "billy the kid", "object_id": "1", "change_message": "Changed item_type, title and author.", "user": 1, "content_type": 17}}, {"pk": 12, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-04 14:29:02", "object_repr": "NewsItem object", "object_id": "1", "change_message": "", "user": 1, "content_type": 16}}, {"pk": 11, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-12-01 07:25:36", "object_repr": "billy--INSTR--1020", "object_id": "1", "change_message": "", "user": 1, "content_type": 15}}, {"pk": 10, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-28 09:35:20", "object_repr": "billy", "object_id": "1", "change_message": "", "user": 1, "content_type": 17}}, {"pk": 9, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-28 09:34:24", "object_repr": "1020", "object_id": "1", "change_message": "", "user": 1, "content_type": 14}}, {"pk": 8, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-28 09:34:09", "object_repr": "spring", "object_id": "1", "change_message": "", "user": 1, "content_type": 12}}, {"pk": 7, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-24 15:32:07", "object_repr": "UserProfile(billy)", "object_id": "1", "change_message": "", "user": 1, "content_type": 9}}, {"pk": 6, "model": "admin.logentry", "fields": {"action_flag": 2, "action_time": "2008-11-24 15:04:45", "object_repr": "billy", "object_id": "3", "change_message": "Changed first_name, last_name, email, is_staff and user_permissions.", "user": 1, "content_type": 3}}, {"pk": 5, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-24 15:04:04", "object_repr": "billy", "object_id": "3", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 4, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-24 15:02:53", "object_repr": "Ancient Socks", "object_id": "1", "change_message": "", "user": 1, "content_type": 13}}, {"pk": 3, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-24 15:02:33", "object_repr": "test1", "object_id": "2", "change_message": "", "user": 1, "content_type": 10}}, {"pk": 2, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-24 13:45:34", "object_repr": "ping", "object_id": "2", "change_message": "", "user": 1, "content_type": 3}}, {"pk": 1, "model": "admin.logentry", "fields": {"action_flag": 1, "action_time": "2008-11-23 22:48:24", "object_repr": "testing", "object_id": "1", "change_message": "", "user": 1, "content_type": 10}}, {"pk": 1, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 3, "home_phone": "444-4444", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 2, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 4, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 3, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 5, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 4, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 6, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 5, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 7, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 6, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 8, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 7, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 9, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 8, "model": "syrup.userprofile", "fields": {"home_address": "", "access_level": null, "user": 10, "home_phone": "", "active": true, "ils_userid": "", "instructor": true, "proxy": false}}, {"pk": 1, "model": "syrup.libraryunit", "fields": {"url": "http://www.testing.org/", "contact_email": "testing@testing.org", "nickname": "testing", "name": "testing"}}, {"pk": 2, "model": "syrup.libraryunit", "fields": {"url": "http://test.net/", "contact_email": "test@org.net", "nickname": "testing", "name": "test1"}}, {"pk": 1, "model": "syrup.term", "fields": {"start": "2008-11-28", "code": "spring", "name": "spring semester", "finish": "2008-12-31"}}, {"pk": 1, "model": "syrup.department", "fields": {"abbreviation": "socks", "active": true, "name": "Ancient Socks"}}, {"pk": 1, "model": "syrup.course", "fields": {"term": 1, "code": "1020", "title": "socks and shirts", "enrol_codes": "", "active": true, "moderated": false, "department": 1}}, {"pk": 1, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 3}}, {"pk": 2, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 4}}, {"pk": 3, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 6}}, {"pk": 4, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 5}}, {"pk": 5, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 7}}, {"pk": 6, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 8}}, {"pk": 7, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 9}}, {"pk": 8, "model": "syrup.member", "fields": {"course": 1, "role": "INSTR", "user": 10}}, {"pk": 1, "model": "syrup.item", "fields": {"parent_heading": null, "performer": "", "isbn": "", "course": 1, "sort_order": 0, "activation_date": "2008-11-28", "oclc": "", "local_control_key": "", "requested_loan_period": "", "call_number": "", "author": "billy and bob: the untold story of billy bob", "source": "", "volume_title": "", "pages_times": "", "mime_type": "text/html", "barcode": "", "volume_edition": "", "last_modified": "2008-11-28 09:35:09", "content_notes": "", "fileobj": "", "home_library": 1, "issn": "", "url": "", "expiration_date": null, "title": "billy the kid", "item_type": "PHYS", "phys_status": "ACTIVE", "date_created": "2008-11-28 09:35:20"}}, {"pk": 1, "model": "syrup.newsitem", "fields": {"body": "The Library is pleased to announce that new funding has come through for constructing a new building. This will realize the architecture put forward in the recent visioning exercise.", "published": "2008-12-04 14:27:16", "encoding": "html", "subject": "Library receives funding for new building"}}]
+++ /dev/null
-# fairly straight mapping of Reserves Direct tables
-# a couple of additions as noted below
-
-from django.db import models
-
-class User(models.Model):
- username = models.CharField(max_length=200,db_index=True)
- first_name = models.CharField(max_length=255,db_index=True)
- last_name = models.CharField(max_length=255,db_index=True)
- email = models.EmailField()
- dflt_permission_level = models.IntegerField(default=0)
- last_login = models.DateTimeField(auto_now=False,null=True,blank=True)
- old_id = models.IntegerField(null=True,blank=True)
- old_user_id = models.IntegerField(null=True,blank=True)
-
- def __unicode__(self):
- return self.username
-
-class LibraryUnit(models.Model):
- name = models.CharField(max_length=100)
- nickname = models.CharField(max_length=15,blank=True,default='')
- ils_prefix = models.CharField(max_length=10,blank=True,default='')
- reserve_desk = models.CharField(max_length=50,blank=True,default='')
- url = models.URLField()
- contact_email = models.EmailField()
- #not sure i understand this, guessing that this is a related library for material type
- copyright_library_id = models.IntegerField(null=True,blank=True)
- monograph_library_id = models.IntegerField(null=True,blank=True)
- multimedia_library_id = models.IntegerField(null=True,blank=True)
-
- def __unicode__(self):
- return self.name
-
-class Item(models.Model):
- title = models.CharField(max_length=255,db_index=True)
- author = models.CharField(max_length=255,db_index=True)
- source = models.CharField(max_length=255,db_index=True)
- volume_title = models.CharField(max_length=255,db_index=True)
- content_notes = models.CharField(max_length=255)
- volume_edition = models.CharField(max_length=255)
- content_notes = models.CharField(max_length=255)
- volume_edition = models.CharField(max_length=255)
- pages_times = models.CharField(max_length=255)
- performer = models.CharField(max_length=255,db_index=True)
- local_control_key = models.CharField(max_length=30)
- creation_date = models.DateField(auto_now=False)
- last_modified = models.DateField(auto_now=False)
- url = models.URLField()
- mime_type = models.CharField(max_length=100,default='text/html')
- home_library = models.ForeignKey(LibraryUnit,related_name='home_library')
- private_user_id = models.IntegerField(null=True,blank=True)
- item_group = models.CharField(max_length=25,default='0')
- ITEM_TYPE_CHOICES = (
- ('ITEM', 'Item'),
- ('HEADING', 'Heading')
- )
- item_type = models.CharField(max_length=7,
- choices=ITEM_TYPE_CHOICES,
- default='ITEM'
- )
- item_icon = models.CharField(max_length=255)
- ISBN = models.CharField(max_length=13,db_index=True)
- ISSN = models.CharField(max_length=8,db_index=True)
- OCLC = models.CharField(max_length=9,db_index=True)
- old_id = models.IntegerField(null=True,blank=True)
-
- def __unicode__(self):
- return self.title
-
-
-class Department(models.Model):
- library = models.ForeignKey(LibraryUnit)
- abbreviatopn = models.CharField(max_length=8,db_index=True)
- name = models.TextField(db_index=True)
- status = models.IntegerField(null=True,blank=True)
-
- def __unicode__(self):
- return self.name
-
-class Course(models.Model):
- department = models.ForeignKey(Department)
- course_number = models.CharField(max_length=50,db_index=True)
- course_name = models.TextField()
- uniform_title = models.TextField(db_index=True)
- old_id = models.IntegerField(null=True,blank=True,db_index=True)
- dept_abv = models.CharField(max_length=50,blank=True,default='')
- old_course_number = models.CharField(max_length=50,blank=True,default='')
-
- def __unicode__(self):
- return self.course_name
-
-class CourseNoDept(models.Model):
- course_number = models.CharField(max_length=50)
- course_name = models.TextField()
- uniform_title = models.BooleanField(default=True)
- old_id = models.IntegerField(null=True,blank=True,db_index=True)
- dept_abv = models.CharField(max_length=50,blank=True,default='')
- old_course_number = models.CharField(max_length=50,blank=True,default='')
-
- def __unicode__(self):
- return self.course_number
-
-class CourseInstance(models.Model):
- primary_course_alias_id = models.IntegerField(null=True,blank=True)
- term = models.CharField(max_length=12,blank=True,default='')
- year = models.IntegerField(default=0)
- activation_date = models.DateTimeField(auto_now=False,db_index=True)
- expiration_date = models.DateTimeField(auto_now=False,db_index=True)
- STATUS_CHOICES = (
- ('ACTIVE', 'Active'),
- ('INACTIVE', 'InActive'),
- ('INPROGRESS', 'In Progress'),
- ('AUTOFEED', 'AutoFeed'),
- ('CANCELLED', 'Cancelled')
- )
- status = models.CharField(max_length=10,
- blank=True,
- choices=STATUS_CHOICES,
- default=''
- )
- ENROLLMENT_CHOICES = (
- ('OPEN', 'Open'),
- ('MODERATED', 'Moderated'),
- ('CLOSED', 'Closed')
- )
- enrollment = models.CharField(max_length=9,
- choices=ENROLLMENT_CHOICES,
- default='OPEN'
- )
- reviewed_date = models.DateTimeField(auto_now=False)
- #what number does this refer to, maybe institutional?
- reviewed_by = models.IntegerField(null=True,blank=True)
-
-class CourseAliasIdent(models.Model):
- course = models.ForeignKey(Course)
- course_name = models.CharField(max_length=200,db_index=True)
- course_instance_id = models.IntegerField(null=True,blank=True)
- course_name = models.TextField()
- section = models.CharField(max_length=25)
- registrar_key = models.CharField(max_length=255)
-
- def __unicode__(self):
- return self.course_name
-
-class PermissionsLevel(models.Model):
- label = models.CharField(max_length=25)
-
- def __unicode__(self):
- return self.label
-
-class AccessLevel(models.Model):
- user = models.ForeignKey(User)
- course_alias = models.ForeignKey(CourseAliasIdent)
- permissions_level = models.IntegerField(default=0, db_index=True)
- ENROLLMENT_STATUS_CHOICES = (
- ('AUTOFEED', 'AutoFeed'),
- ('APPROVED', 'Approved'),
- ('PENDING', 'Pending'),
- ('DENIED', 'Denied')
- )
- enrollment_status = models.CharField(max_length=8,
- choices=ENROLLMENT_STATUS_CHOICES,
- default='PENDING'
- )
- autofeed_run_indicator = models.CharField(max_length=20)
-
-class CircRule(models.Model):
- circ_rule = models.CharField(max_length=50,blank=True,default='')
- alt_circ_rule = models.CharField(max_length=50,blank=True,default='')
- default_selected = models.BooleanField(default=False)
-
- def __unicode__(self):
- return self.circ_rule
-
-class ElectronicItemAudit(models.Model):
- item_id = models.IntegerField(default=0)
- date_added = models.DateField(auto_now_add=True)
- date_reviewed = models.DateField(auto_now=False)
- added_by = models.IntegerField(null=True,blank=True)
- reviewed_by = models.IntegerField(null=True,blank=True)
-
-class Reserve(models.Model):
- course_instance = models.ForeignKey(CourseInstance)
- item = models.ForeignKey(Item)
- activation_date = models.DateField(auto_now=False)
- STATUS_CHOICES = (
- ('ACTIVE', 'Active'),
- ('INACTIVE', 'InActive'),
- ('INPROCESS', 'In Process')
- )
- status = models.CharField(max_length=9,
- blank=True,
- choices=STATUS_CHOICES,
- default=''
- )
- expiration = models.DateField(auto_now=False)
- date_created = models.DateTimeField(auto_now_add=True)
- last_modified = models.DateTimeField()
- requested_loan_period = models.CharField(max_length=255,blank=True,default='')
- parent_id = models.IntegerField(null=True,blank=True)
-
-class HiddenReading(models.Model):
- user = models.ForeignKey(User)
- reserve = models.ForeignKey(Reserve)
-
-class IlsRequest(models.Model):
- date_added = models.DateField(auto_now_add=True)
- #whoa, need to do homework on this
- ils_request_id = models.CharField(max_length=16,db_index=True)
- ils_control_key = models.CharField(max_length=16,db_index=True)
- user_net_id = models.CharField(max_length=16,db_index=True)
- user_ils_id = models.CharField(max_length=16,db_index=True)
- ils_course = models.CharField(max_length=150,db_index=True)
- requested_loan_period = models.CharField(max_length=16)
-
- def __unicode__(self):
- return self.ils_request_id
-
-class InstLoadPeriod(models.Model):
- loan_period = models.CharField(max_length=255,blank=True,default='')
-
- def __unicode__(self):
- return self.loan_period
-
-class InstLoadPeriodLibraryUnit(models.Model):
- library = models.ForeignKey(LibraryUnit)
- loan_period = models.ForeignKey(InstLoadPeriod)
- default= models.BooleanField(default=False)
-
-class InstructorAttribute(models.Model):
- user = models.ForeignKey(User)
- ils_user_id = models.CharField(max_length=50)
- ils_name = models.CharField(max_length=75)
- organizational_status = models.CharField(max_length=25)
-
-class ItemUploadLog(models.Model):
- user = models.ForeignKey(User)
- course_instance = models.ForeignKey(CourseInstance)
- item = models.ForeignKey(Item)
- timestamp_uploaded = models.DateTimeField()
- filesize = models.CharField(max_length=10,blank=True,default='')
- ipaddr = models.IPAddressField()
-
-class NewsItem(models.Model):
- news_text = models.TextField()
- font_class = models.CharField(max_length=50,blank=True,default='')
- PERMISSIONS_LEVEL_CHOICES = (
- ('0', '0 - '),
- ('1', '1 - '),
- ('2', '2 - '),
- ('3', '3 - '),
- ('4', '4 - '),
- ('5', '5 - ')
- )
- permissions_level = models.CharField(max_length=1,
- choices=PERMISSIONS_LEVEL_CHOICES,
- blank=True,
- default=''
- )
-
- def __unicode__(self):
- return self.news_text
-
-class NotTrained(models.Model):
- user = models.ForeignKey(User)
- permission_level = models.IntegerField(default=0)
-
-class Note(models.Model):
- type = models.CharField(max_length=25,blank=True,default='')
- target_id = models.IntegerField(default=0)
- note = models.TextField()
- target = models.CharField(max_length=50,blank=True,default='')
-
- def __unicode__(self):
- return self.note
-
-class PhysicalCopyItem(models.Model):
- reserve = models.ForeignKey(Reserve)
- item = models.ForeignKey(Item)
- status = models.CharField(max_length=30,blank=True,default='')
- call_number = models.TextField()
- owning_library = models.CharField(max_length=15,default='0')
- item_type = models.CharField(max_length=30)
- owner_user_id = models.IntegerField(null=True,blank=True)
-
-class ProxyIdent(models.Model):
- name = models.CharField(max_length=50,blank=True,default='')
- prefix = models.CharField(max_length=255,blank=True,default='')
-
- def __unicode__(self):
- return self.name
-
-class ProxiedHost(models.Model):
- proxy = models.ForeignKey(ProxyIdent)
- domain = models.CharField(max_length=255,blank=True,default='')
- partial_match = models.BooleanField(default=False)
-
-class Request(models.Model):
- reserve = models.ForeignKey(Reserve)
- item = models.ForeignKey(Item)
- user = models.ForeignKey(User)
- date_requested = models.DateField()
- date_processed = models.DateField(auto_now=False)
- date_desired = models.DateField(auto_now=False)
- priority = models.IntegerField(null=True,blank=True)
- course_instance = models.ForeignKey(CourseInstance)
-
-class Report(models.Model):
- title = models.CharField(max_length=255)
- PARAM_GROUP_CHOICES = (
- ('TERM', 'Term'),
- ('DEPARTMENT', 'Department'),
- ('CLASS', 'Class'),
- ('TERM_LIB', 'Term Lib'),
- ('TERM_DATES', 'Term Dates')
- )
- param_group = models.CharField(max_length=10,
- blank=True,
- choices=PARAM_GROUP_CHOICES,
- default=''
- )
- sql = models.TextField()
- parameters = models.CharField(max_length=255)
- min_permissions = models.IntegerField(default=4)
- sort_order = models.IntegerField(default=0)
- cached = models.BooleanField(default=True)
- cached_refresh_delay = models.IntegerField(default=6)
-
- def __unicode__(self):
- return self.title
-
-class ReportCache(models.Model):
- report = models.ForeignKey(Report)
- params_cache = models.TextField()
- reports_cache = models.TextField()
- last_modified = models.DateTimeField()
-
-class Skin(models.Model):
- skin_name = models.CharField(max_length=25,blank=True,default='')
- skin_stylesheet = models.TextField()
- default_selected = models.BooleanField(default=False)
-
- def __unicode__(self):
- return self.skin_name
-
-class SpecialUser(models.Model):
- user = models.ForeignKey(User)
- password = models.CharField(max_length=75,blank=True,default='')
- expiration = models.DateField(null=True,blank=True)
-
-class SpecialUserAudit(models.Model):
- user = models.ForeignKey(User)
- creator = models.ForeignKey(User,related_name='creator')
- date_created = models.DateTimeField(auto_now_add=True)
- email_sent_to = models.CharField(max_length=255)
-
-class StaffLibraryUnit(models.Model):
- user = models.ForeignKey(User)
- library = models.ForeignKey(LibraryUnit)
- permission_level = models.IntegerField(default=0)
-
-class Term(models.Model):
- sort_order = models.IntegerField(default=0)
- term_name = models.CharField(max_length=100,default='')
- term_year = models.CharField(max_length=4,default='')
- begin_date = models.DateField(auto_now=False)
- end_date = models.DateField(auto_now=False)
-
- def __unicode__(self):
- return self.term_name
-
-class UserViewLog(models.Model):
- user = models.ForeignKey(User)
- reserve = models.ForeignKey(Reserve)
- timestamp_viewed = models.DateTimeField()
-
-class MimeType(models.Model):
- mime_type = models.CharField(max_length=100,default='')
- helper_app_url = models.TextField()
- helper_app_name = models.TextField()
- helper_app_icon = models.TextField()
- file_extensions = models.CharField(max_length=255,blank=True,default='')
-
- def __unicode__(self):
- return self.mime_type
-
-class HelpCategoryItem(models.Model):
- title = models.CharField(max_length=100)
- description = models.TextField()
-
- def __unicode__(self):
- return self.title
-
-class HelpArticle(models.Model):
- title = models.CharField(max_length=100)
- date_created = models.DateField(auto_now_add=True)
- body = models.TextField()
- date_modified = models.DateField()
-
- def __unicode__(self):
- return self.title
-
-class HelpArticleTag(models.Model):
- help_article = models.ForeignKey(HelpArticle)
- user = models.ForeignKey(User)
- tag = models.CharField(max_length=50)
-
-class HelpCatToRole(models.Model):
- permission_level = models.IntegerField(default=0)
- can_view = models.BooleanField(default=False)
- can_edit = models.BooleanField(default=False)
-
- def __unicode__(self):
- return self.permission_level
-
-class HelpArticleToRole(models.Model):
- help_article = models.ForeignKey(HelpArticle)
- permission_level = models.IntegerField(default=0)
- can_view = models.BooleanField(default=False)
- can_edit = models.BooleanField(default=False)
-
-class HelpArticleToArticle(models.Model):
- help_article1 = models.ForeignKey(HelpArticle,related_name='help_article1')
- help_article2 = models.ForeignKey(HelpArticle,related_name='help_article2')
- RELATION_2TO1_CHOICES = (
- ('CHILD', 'Child'),
- ('SIBLING', 'Sibling')
- )
- relation_2to1 = models.CharField(max_length=7,
- blank=True,
- choices=RELATION_2TO1_CHOICES,
- default=''
- )
+++ /dev/null
-# -*- mode: text; mode: auto-fill; -*-
-
-
-Fleshing out the course model
---------------------------------------------------
-
-These are just some stream-of-thought notes; don't take them too
-seriously yet.
-
-
-
-We should capitalize on external data sources for course and
-registration information. At the same time, it must be possible to
-use Syrup without an external source, or in a mixed mode (where some
-courses are defined externally and others are ad-hoc).
-
-There will be local variations in the quality of course information.
-Possibly some can provide lists of known courses, but not registration
-information; others will know students enrolled but may not know
-instructors (or vice versa).
-
-So, in fact we have a number of granular external sources, and Syrup
-should operate with any combination of them.
-
-* list of terms (but allowing ad-hoc terms);
-
-* list of course codes and titles (not time- or term-related);
-
-* list of offerings (course-code offered in term);
-
-* list of sections (same course offered several times in one term,
- and/or broken up into multiple subgroups. Some reserve courses may
- aggregate some sections, excluding others). Sections are ultimately
- the join-points between instructors and students, so we must handle
- them well;
-
-* cross-listings (equivalent course-codes);
-
-* people (username/identifier, given, surname, email)
-
-* instructor and student relationships (fred teaches FRE233/2009W/01;
- bill takes ESP125/2009W/03).
-
-
-Rolls-Royce Scenario
---------------------------------------------------
-
-Shelley Smith wants to set up a reserves-site for the course she's
-teaching next term. She logs into reserves, clicks on My Courses, and
-clicks Add a New Course Site. The form asks her to pick a term (the
-current term is the default, all future terms are listed in a
-drop-down), and to pick a course. The system suggests the courses she
-is currently teaching; but this is for a future term, and she's not
-the instructor of record yet, so she picks the code and title from a
-drop-down list.
-
-She doesn't specify any sections, since she won't know that for a few
-months yet. The site remains unavailable to students until she does.
-
-Later, she clicks on Invite Students. It asks her to pick the
-course-sections she's teaching from a list. It knows her course is
-cross-listed; the cross-list sections also appear on the list.
-
-Once the sections are selected, and she presses Continue, the students
-are granted access.
-
- Variation: staff-assistance
- --------------------------------------------------
-
- Shelley contacts Ed at the Reserves desk, and tells him she wants to
- put some items on reserve. She's teaching MAC-100, Intro to Macrame,
- section 2, in the upcoming term.
-
- Ed clicks on Assist, and finds Shelley's in the people-list, and
- selects her. He clicks on Shelley's Courses, then Add New Course,
- and enters the term and picks MAC-100 from the list. He knows the
- section so is able to add that right away. The system alerts him to
- the cross-listed section, and he adds that too.
-
- The site won't be ready for students until he (or Shelley) activates
- the site later on.
-
- Shelley gets an email letting her know the site is ready for
- content.
-
- Data sources
- --------------------------------------------------
-
- Shelley and Ed logged in against campus LDAP.
-
- Shelley's current courses and
-
-
-
-Another take
-------------------------------------------------------------
-
-Shelley can set up the course well in advance, with a trivial working
-title, e.g. "Macrame". It's one of Shelley's courses, but no one else
-has access, and it's not associated with any term, etc.
-
- Instructor: course-add
- Library-Staff: course-add
-
-Later, when Shelley is ready to open her reserves to her students, she
-opens the site and hits Invite. What appears is a list of the course
-sections she is teaching:
-
- MAC-100 section 02 -- Introduction to Macrame (58 members)
- MAC-301 section 01 -- Macrame Advanced Studio (2 members)
- LAB-203 section 01 -- Macrame in Labour Studies (8 members)
-
-She checkmarks the first and last section, and presses Invite.
-Automatically, her site is available to her students, but it also gets
-a proper title and course number: she is asked to pick either MAC-100
-or LAB-203 as the primary identifier for the site; the other becomes
-an alias.
-
-Later calls Ed -- she's talked with the instructor of Textiles 101,
-and they've agreed to share Shelley's reserves list with the Textiles
-class. She cannot add an arbitrary section to the course site. So Ed
-opens the site; clicks on Invite; clicks Arbitrary Section; and
-specifies the term, course code, and section of the Textiles class.
-
- Instructor: course-section-invite
- Library-Staff: course-section-invite-arbitrary
-
-A key point here is that the formal course numbers may not be
-selectable until late in the game; until just before the course, a
-working title may be all that you have. That's fine. Choosing specific
-course sections can be deferred until the registration info is
-available.
-
-
-What about the case where there is no registration data? How do you
-make a site available to an unknown audience?
-
-Have controls for "publishing" a site, that is, making it available to
-unknown users. A few options:
-
- * Anyone at all can view the site, even anonymously
-
- * Any logged-in user can view the site
-
- * The instructor provides an access key out-of-band. The access key
- auto-invites you into the site. This isn't so bad really.
-
- * Any logged-in user can request access; the instructor has to grant
- access. This way lies madness.
-
-Scrapping the madness-path, we're left with a reasonable set of
-options: Anonymous, Authenticated, AccessKey, Restricted (to members
-of the registered list), or NoAccess (for archived sites, etc.). None
-of this applies to instructors and their proxies, just to visitors.
-
- Instructor: course-change-access
- Library-Staff: course-change-access-extended
-
- The extended permissions could let the librarian decide if certain
- types of materials in the site should be inaccessible to Anonymous
- users. Or maybe we should just scrap Anonymous access altogether.
if item.item_type == 'HEADING':
return _heading_detail(request, item)
else:
- return g.render('item_metadata.xhtml', course=item.course,
+ return g.render('item/item_metadata.xhtml', course=item.course,
item=item)
def _heading_url(request, item):
def _heading_detail(request, item):
"""Display a heading. Show the subitems for this heading."""
- return g.render('item_heading_detail.xhtml', item=item)
+ return g.render('item/item_heading_detail.xhtml', item=item)
@instructors_only
if request.method != 'POST':
item = models.Item() # dummy object
metadata_formset = metadata_formset_class(queryset=item.metadata_set.all())
- return g.render('item_add_%s.xhtml' % item_type.lower(),
+ return g.render('item/item_add_%s.xhtml' % item_type.lower(),
**locals())
else:
# fixme, this will need refactoring. But not yet.
#----------
if request.method != 'POST':
- return g.render('item_add_cat_search.xhtml', results=[], query='',
+ return g.render('item/item_add_cat_search.xhtml', results=[], query='',
course=course, parent_item=parent_item)
# POST handler
# process the query.
assert query, 'must provide a query.'
results = lib_integration.cat_search(query)
- return g.render('item_add_cat_search.xhtml',
+ return g.render('item/item_add_cat_search.xhtml',
results=results, query=query,
course=course, parent_item=parent_item)
else:
course = get_object_or_404(models.Course, pk=course_id)
item = get_object_or_404(models.Item, pk=item_id, course__id=course_id)
if request.method != 'POST':
- return g.render('item_delete_confirm.xhtml', **locals())
+ return g.render('item/item_delete_confirm.xhtml', **locals())
else:
if 'yes' in request.POST:
# I think Django's ON DELETE CASCADE-like behaviour will
course = get_object_or_404(models.Course, pk=course_id)
item = get_object_or_404(models.Item, pk=item_id, course__id=course_id)
if request.method != 'POST':
- return g.render('item_relocate.xhtml', **locals())
+ return g.render('item/item_relocate.xhtml', **locals())
else:
newheading = int(request.POST['heading'])
if newheading == 0:
--- /dev/null
+<?python
+from django.utils.simplejson import dumps
+from conifer.libsystems.z3950.marcxml import marcxml_dictionary_to_dc as to_dublin
+title = _('Add physical item: Catalogue search')
+dc_keys = ['dc:title', 'dc:creator', 'dc:publisher', 'dc:date']
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+<xi:include href="../master.xhtml"/>
+<xi:include href="paginate.xhtml"/>
+<xi:include href="../components/course.xhtml"/>
+<head>
+ <title>${title}</title>
+ <script type="text/javascript">
+ <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
+ $(function() { $('.pagetable').tablesorter(); });
+ </script>
+ <script py:if="request.method != 'POST'"> <!-- !focus on query box if nothing to scroll. -->
+ $(function() { $('#query').focus(); });
+ </script>
+</head>
+<body>
+ ${course_banner(course)}
+ ${nested_title(parent_item)}
+ <h2>${title}</h2>
+ <form method="POST" action=".">
+ <input type="text" id="query" name="query" value="${query}"
+ style="font-size: larger; width: 600;"/>
+ <input type="submit" value="Search"/>
+ </form>
+
+ <table class="pagetable" py:if="request.method == 'POST'">
+ <thead>
+ <tr><th>Title</th><th>Author</th><th>Publisher</th><th>PubDate</th></tr>
+ </thead>
+ <tbody py:for="resultnum, res in enumerate(results)"
+ py:with="dc=to_dublin(res)">
+ <tr>
+ <td>
+ ${dc.get('dc:title', '???')}
+ <a href="javascript:$('#full_${resultnum}').toggle(); void(0);">details</a>
+ </td>
+ <td py:for="k in dc_keys[1:]">${dc.get(k) or '—'}</td>
+ <td>
+ <form action="." method="POST">
+ <input type="hidden" name="pickitem" value="${dumps(res)}"/>
+ <input type="submit" value="Pick this item"/>
+ </form>
+ </td>
+ </tr>
+ <tr id="full_${resultnum}" style="display: none;">
+ <td colspan="4" style="padding-left: 36;">
+ <table class="metadata_table">
+ <?python allkeys = res.keys(); allkeys.sort(); ?>
+ <tr py:for="k in allkeys">
+ <th>${k}</th><td>${res[k]}</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+</html>
--- /dev/null
+<?python
+is_edit = bool(item.id)
+title = is_edit and _('Edit an electronic document') or _('Add a new electronic document')
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript">
+ $(function() {$('input[name="title"]').focus();});
+ </script>
+ ${item_metadata_formset_header()}
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(parent_item)}
+ ${offer_to_delete(item)}
+ <h2>${title}</h2>
+ <div py:if="not is_edit">
+ <form action=".?item_type=${item_type}" method="POST"
+ enctype="multipart/form-data">
+ <table class="metadata_table">
+ <tr><th>Title of document</th><td><input type="text"
+ name="title"
+ value="${item.title}"/></td></tr>
+ <tr><th>File</th><td><input type="file" name="file"/></td></tr>
+ </table>
+ ${item_metadata_formset()}
+ <p><input type="submit" value="Upload file and Create item"/></p>
+ </form>
+ </div>
+
+ <div py:if="is_edit">
+ <form action="." method="POST">
+ <table class="metadata_table">
+ <tr><th>Title of document</th><td><input type="text" name="title"
+ value="${item.title}"/></td></tr>
+ </table>
+ ${item_metadata_formset()}
+ <p><input type="submit" value="Update title and metadata"/></p>
+ </form>
+ <h2>File contents</h2>
+ <form action="." method="POST" enctype="multipart/form-data">
+ <table class="metadata_table">
+ <tr><th>File</th><td><input type="file" name="file"/></td></tr>
+ </table>
+ <p><input type="submit" value="Upload new file contents"/></p>
+ </form>
+ </div>
+</body>
+</html>
--- /dev/null
+<?python
+is_edit = bool(item.id)
+title = is_edit and _('Edit a subheading') or _('Add a new subheading')
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript">
+ $(function() {$('input[name="title"]').focus();});
+ </script>
+ ${item_metadata_formset_header()}
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(parent_item)}
+ ${offer_to_delete(item)}
+ <h2>${title}</h2>
+ <form action=".?item_type=${item_type}" method="POST">
+ <table class="metadata_table">
+ <tr><th>Heading</th><td>
+ <input type="text" name="title"
+ value="${item.title}"/>
+ </td></tr>
+ </table>
+ ${item_metadata_formset()}
+ <p>
+ <input py:if="not is_edit" type="submit" value="Add heading"/>
+ <input py:if="is_edit" type="submit" value="Update heading"/>
+ </p>
+
+ </form>
+</body>
+</html>
--- /dev/null
+<?python
+is_edit = bool(item.id)
+title = is_edit and _('Edit a physical-item request') or _('Add a physical-item request')
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript">
+ $(function() {$('input[name="title"]').focus();});
+ </script>
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(parent_item)}
+ <div id="sidepanel">${offer_to_delete(item)}</div>
+ <h2>${title}</h2>
+
+ <form action=".?item_type=${item_type}" method="POST">
+ <table class="metadata_table">
+ <tr>
+ <th>Display name</th>
+ <td><input type="text" name="title" value="${item.title}"/></td>
+ </tr>
+ </table>
+ <h2>Metadata</h2>
+ ${item_metadata_formset(show_more=False)}
+ <p>
+ <input py:if="not is_edit" type="submit" value="Add heading"/>
+ <input py:if="is_edit" type="submit" value="Update physical-item request"/>
+ </p>
+
+ </form>
+</body>
+</html>
--- /dev/null
+<?python
+is_edit = bool(item.id)
+title = is_edit and _('Edit a URL') or _('Add a new URL')
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript">
+ $(function() {$('input[name="title"]').focus();});
+ </script>
+ ${item_metadata_formset_header()}
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(parent_item)}
+ ${offer_to_delete(item)}
+ <h2>${title}</h2>
+ <form action=".?item_type=${item_type}" method="POST">
+ <table class="metadata_table">
+ <tr><th>Title</th><td><input type="text" name="title" value="${item.title}"/></td></tr>
+ <tr><th>URL</th><td><input type="text" name="url" value="${item.url}"/></td></tr>
+ </table>
+ ${item_metadata_formset()}
+ <p>
+ <input py:if="not is_edit" type="submit" value="Add URL"/>
+ <input py:if="is_edit" type="submit" value="Update URL"/>
+ </p>
+ </form>
+</body>
+</html>
--- /dev/null
+<?python
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+hier = item.hierarchy()[:-1]
+if item.item_type == 'HEADING':
+ title = _('Delete this heading?')
+ children = item.children()
+else:
+ title = _('Delete this item?')
+ children = []
+metadata = item.metadata_set.all()
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(item)}
+ <h1>${title}</h1>
+ <p>Are you sure you want to delete this?</p>
+ <p py:if="children">
+ <strong>Note: this will also delete all items under the heading!</strong>
+ </p>
+ <table class="metadata_table" style="margin-top: 1em;">
+ <tr><th>Title</th><td>${item.title}</td></tr>
+ <tr><th>Type</th><td>${item.get_item_type_display()}</td></tr>
+ <tr py:if="item.url"><th>URL</th><td><a href="${item.url}">${item.url}</a></td></tr>
+ </table>
+ <p>
+ <form action="." method="POST">
+ <input type="submit" name="yes" value="Yes, delete it" style="padding: 4 12; margin-right: 24;"/>
+ <input type="submit" name="no" value="Cancel"/>
+ </form>
+ </p>
+ </body>
+</html>
+
--- /dev/null
+<?python
+course = item.course
+title = item.title
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+is_editor = course.can_edit(request.user)
+item_tree = course.item_tree(subtree=item)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
+ </head>
+ <body>
+ ${course_banner(course)}
+ <div py:if="is_editor" id="sidepanel" class="little_action_panel">
+ <div>
+ <a href="edit/">Edit this heading</a>
+ </div>
+ <div>
+ <a href="delete/">Delete this heading</a>
+ </div>
+ <div>
+ <a href="relocate/">Relocate this heading</a>
+ </div>
+ <div>${item_resequence_panel()}</div>
+ </div>
+ ${nested_title(item)}
+
+ <p py:if="not item_tree">
+ There are no items in this section.
+ </p>
+ <div id="treepanel">
+ ${show_tree(item_tree, edit=is_editor)}
+ </div>
+ <div py:if="is_editor">${add_subs(item)}</div>
+ </body>
+</html>
--- /dev/null
+<?python
+from django.utils.simplejson import loads
+course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
+hier = item.hierarchy()[:-1]
+title = item.title
+smallint = item.smallint()
+metadata = item.metadata_set.all()
+is_editor = course.can_edit(request.user)
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <style>
+ .available { color: green; border-left: 16px green solid; padding-left: 8px; }
+ .unavailable { color: red; border-left: 16px red solid; padding-left: 8px; }
+ </style>
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(item)}
+ <div py:if="is_editor" id="sidepanel">
+ <div>
+ <a href="edit/">Edit this item</a>
+ </div>
+ <div>
+ <a href="delete/">Delete this item</a>
+ </div>
+ <div>
+ <a href="relocate/">Relocate this item</a>
+ </div>
+ </div>
+ <table class="metadata_table" style="margin-top: 1em;">
+ <tr><th>Title</th><td>${item.title}</td></tr>
+ <tr><th>Type</th><td>${item.get_item_type_display()}</td></tr>
+ <tr py:if="item.item_type=='PHYS'"
+ py:with="avail, status = item.describe_physical_item_status()">
+ <th>Status</th><td><div class="${avail and 'available' or 'unavailable'}">${status}</div></td>
+ </tr>
+ <tr py:if="smallint">
+ <th>Small Number</th><td>${smallint}</td>
+ </tr>
+ <tr py:if="item.url"><th>URL</th><td><a href="${item.url}">${item.url}</a></td></tr>
+ </table>
+ <div py:if="item.item_type=='ELEC'">
+ <h2 class="metadata_subhead">Attached document</h2>
+ <table class="metadata_table">
+ <tr><th>Content type</th><td>${item.fileobj_mimetype}</td></tr>
+ <tr><th>Size</th><td>${item.fileobj.size} bytes</td></tr>
+ <tr><th/><td><a class="bigdownload" href="${item.item_url()}">Download</a></td></tr>
+ </table>
+ </div>
+ <div py:if="metadata">
+ <h2 class="metadata_subhead">Additional metadata</h2>
+ <table class="metadata_table">
+ <tr py:for="attr in metadata">
+ <th>${attr.get_name_display()}</th>
+ <td py:if="attr.name != 'syrup:marc'">
+ ${attr.value}
+ </td>
+ <td py:if="attr.name == 'syrup:marc'">
+ <div id="marcdatashow"><a href="javascript:$('#marcdata').show();$('#marcdatashow').hide();void(0);">show</a></div>
+ <div id="marcdata" style="display: none;">
+ <?python dct = loads(attr.value); keys=dct.keys(); keys.sort() ?>
+ <table>
+ <tr py:for="k in keys">
+ <th>${k}</th>
+ <td>${dct[k]}</td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </body>
+</html>
--- /dev/null
+<?python
+title = 'Move item under a different heading'
+?>
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xmlns:py="http://genshi.edgewall.org/">
+ <xi:include href="../master.xhtml"/>
+ <xi:include href="../components/course.xhtml"/>
+ <head>
+ <title>${title}</title>
+ <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
+ </head>
+ <body>
+ ${course_banner(course)}
+ ${nested_title(item)}
+ <h2>${title}</h2>
+ <p>Please choose the heading under which this item should be moved:</p>
+ <form action="." method="POST">
+ <table class="metadata_table">
+ <tbody style="text-align: left;">
+ <tr><th>Item title:</th><td>${item.title}</td></tr>
+ <tr><th>Current heading:
+ </th><td>${item.parent_heading and item.parent_heading.title or 'Top Level'}
+ <div class="gap"/></td></tr>
+ <tr><th>New heading:</th>
+ <td>
+ ${heading_tree(course.item_tree(), stop_at=item)}
+ <div class="gap"/>
+ </td>
+ </tr>
+ <tr>
+ <th/>
+ <td><input type="submit" value="Move item"/></td>
+ </tr>
+ </tbody>
+ </table>
+ </form>
+ </body>
+</html>
+++ /dev/null
-<?python
-from django.utils.simplejson import dumps
-from conifer.libsystems.z3950.marcxml import marcxml_dictionary_to_dc as to_dublin
-title = _('Add physical item: Catalogue search')
-dc_keys = ['dc:title', 'dc:creator', 'dc:publisher', 'dc:date']
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
-<xi:include href="master.xhtml"/>
-<xi:include href="paginate.xhtml"/>
-<xi:include href="components/course.xhtml"/>
-<head>
- <title>${title}</title>
- <script type="text/javascript">
- <!-- !This ought to be in paginate.xhtml, not here. how to do? -->
- $(function() { $('.pagetable').tablesorter(); });
- </script>
- <script py:if="request.method != 'POST'"> <!-- !focus on query box if nothing to scroll. -->
- $(function() { $('#query').focus(); });
- </script>
-</head>
-<body>
- ${course_banner(course)}
- ${nested_title(parent_item)}
- <h2>${title}</h2>
- <form method="POST" action=".">
- <input type="text" id="query" name="query" value="${query}"
- style="font-size: larger; width: 600;"/>
- <input type="submit" value="Search"/>
- </form>
-
- <table class="pagetable" py:if="request.method == 'POST'">
- <thead>
- <tr><th>Title</th><th>Author</th><th>Publisher</th><th>PubDate</th></tr>
- </thead>
- <tbody py:for="resultnum, res in enumerate(results)"
- py:with="dc=to_dublin(res)">
- <tr>
- <td>
- ${dc.get('dc:title', '???')}
- <a href="javascript:$('#full_${resultnum}').toggle(); void(0);">details</a>
- </td>
- <td py:for="k in dc_keys[1:]">${dc.get(k) or '—'}</td>
- <td>
- <form action="." method="POST">
- <input type="hidden" name="pickitem" value="${dumps(res)}"/>
- <input type="submit" value="Pick this item"/>
- </form>
- </td>
- </tr>
- <tr id="full_${resultnum}" style="display: none;">
- <td colspan="4" style="padding-left: 36;">
- <table class="metadata_table">
- <?python allkeys = res.keys(); allkeys.sort(); ?>
- <tr py:for="k in allkeys">
- <th>${k}</th><td>${res[k]}</td>
- </tr>
- </table>
- </td>
- </tr>
- </tbody>
- </table>
- </body>
-</html>
+++ /dev/null
-<?python
-is_edit = bool(item.id)
-title = is_edit and _('Edit an electronic document') or _('Add a new electronic document')
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript">
- $(function() {$('input[name="title"]').focus();});
- </script>
- ${item_metadata_formset_header()}
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(parent_item)}
- ${offer_to_delete(item)}
- <h2>${title}</h2>
- <div py:if="not is_edit">
- <form action=".?item_type=${item_type}" method="POST"
- enctype="multipart/form-data">
- <table class="metadata_table">
- <tr><th>Title of document</th><td><input type="text"
- name="title"
- value="${item.title}"/></td></tr>
- <tr><th>File</th><td><input type="file" name="file"/></td></tr>
- </table>
- ${item_metadata_formset()}
- <p><input type="submit" value="Upload file and Create item"/></p>
- </form>
- </div>
-
- <div py:if="is_edit">
- <form action="." method="POST">
- <table class="metadata_table">
- <tr><th>Title of document</th><td><input type="text" name="title"
- value="${item.title}"/></td></tr>
- </table>
- ${item_metadata_formset()}
- <p><input type="submit" value="Update title and metadata"/></p>
- </form>
- <h2>File contents</h2>
- <form action="." method="POST" enctype="multipart/form-data">
- <table class="metadata_table">
- <tr><th>File</th><td><input type="file" name="file"/></td></tr>
- </table>
- <p><input type="submit" value="Upload new file contents"/></p>
- </form>
- </div>
-</body>
-</html>
+++ /dev/null
-<?python
-is_edit = bool(item.id)
-title = is_edit and _('Edit a subheading') or _('Add a new subheading')
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript">
- $(function() {$('input[name="title"]').focus();});
- </script>
- ${item_metadata_formset_header()}
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(parent_item)}
- ${offer_to_delete(item)}
- <h2>${title}</h2>
- <form action=".?item_type=${item_type}" method="POST">
- <table class="metadata_table">
- <tr><th>Heading</th><td>
- <input type="text" name="title"
- value="${item.title}"/>
- </td></tr>
- </table>
- ${item_metadata_formset()}
- <p>
- <input py:if="not is_edit" type="submit" value="Add heading"/>
- <input py:if="is_edit" type="submit" value="Update heading"/>
- </p>
-
- </form>
-</body>
-</html>
+++ /dev/null
-<?python
-is_edit = bool(item.id)
-title = is_edit and _('Edit a physical-item request') or _('Add a physical-item request')
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript">
- $(function() {$('input[name="title"]').focus();});
- </script>
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(parent_item)}
- <div id="sidepanel">${offer_to_delete(item)}</div>
- <h2>${title}</h2>
-
- <form action=".?item_type=${item_type}" method="POST">
- <table class="metadata_table">
- <tr>
- <th>Display name</th>
- <td><input type="text" name="title" value="${item.title}"/></td>
- </tr>
- </table>
- <h2>Metadata</h2>
- ${item_metadata_formset(show_more=False)}
- <p>
- <input py:if="not is_edit" type="submit" value="Add heading"/>
- <input py:if="is_edit" type="submit" value="Update physical-item request"/>
- </p>
-
- </form>
-</body>
-</html>
+++ /dev/null
-<?python
-is_edit = bool(item.id)
-title = is_edit and _('Edit a URL') or _('Add a new URL')
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript">
- $(function() {$('input[name="title"]').focus();});
- </script>
- ${item_metadata_formset_header()}
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(parent_item)}
- ${offer_to_delete(item)}
- <h2>${title}</h2>
- <form action=".?item_type=${item_type}" method="POST">
- <table class="metadata_table">
- <tr><th>Title</th><td><input type="text" name="title" value="${item.title}"/></td></tr>
- <tr><th>URL</th><td><input type="text" name="url" value="${item.url}"/></td></tr>
- </table>
- ${item_metadata_formset()}
- <p>
- <input py:if="not is_edit" type="submit" value="Add URL"/>
- <input py:if="is_edit" type="submit" value="Update URL"/>
- </p>
- </form>
-</body>
-</html>
+++ /dev/null
-<?python
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-hier = item.hierarchy()[:-1]
-if item.item_type == 'HEADING':
- title = _('Delete this heading?')
- children = item.children()
-else:
- title = _('Delete this item?')
- children = []
-metadata = item.metadata_set.all()
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(item)}
- <h1>${title}</h1>
- <p>Are you sure you want to delete this?</p>
- <p py:if="children">
- <strong>Note: this will also delete all items under the heading!</strong>
- </p>
- <table class="metadata_table" style="margin-top: 1em;">
- <tr><th>Title</th><td>${item.title}</td></tr>
- <tr><th>Type</th><td>${item.get_item_type_display()}</td></tr>
- <tr py:if="item.url"><th>URL</th><td><a href="${item.url}">${item.url}</a></td></tr>
- </table>
- <p>
- <form action="." method="POST">
- <input type="submit" name="yes" value="Yes, delete it" style="padding: 4 12; margin-right: 24;"/>
- <input type="submit" name="no" value="Cancel"/>
- </form>
- </p>
- </body>
-</html>
-
+++ /dev/null
-<?python
-course = item.course
-title = item.title
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-is_editor = course.can_edit(request.user)
-item_tree = course.item_tree(subtree=item)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
- </head>
- <body>
- ${course_banner(course)}
- <div py:if="is_editor" id="sidepanel" class="little_action_panel">
- <div>
- <a href="edit/">Edit this heading</a>
- </div>
- <div>
- <a href="delete/">Delete this heading</a>
- </div>
- <div>
- <a href="relocate/">Relocate this heading</a>
- </div>
- <div>${item_resequence_panel()}</div>
- </div>
- ${nested_title(item)}
-
- <p py:if="not item_tree">
- There are no items in this section.
- </p>
- <div id="treepanel">
- ${show_tree(item_tree, edit=is_editor)}
- </div>
- <div py:if="is_editor">${add_subs(item)}</div>
- </body>
-</html>
+++ /dev/null
-<?python
-from django.utils.simplejson import loads
-course_title = '%s: %s (%s)' % (course.code, course.title, course.term)
-hier = item.hierarchy()[:-1]
-title = item.title
-smallint = item.smallint()
-metadata = item.metadata_set.all()
-is_editor = course.can_edit(request.user)
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <style>
- .available { color: green; border-left: 16px green solid; padding-left: 8px; }
- .unavailable { color: red; border-left: 16px red solid; padding-left: 8px; }
- </style>
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(item)}
- <div py:if="is_editor" id="sidepanel">
- <div>
- <a href="edit/">Edit this item</a>
- </div>
- <div>
- <a href="delete/">Delete this item</a>
- </div>
- <div>
- <a href="relocate/">Relocate this item</a>
- </div>
- </div>
- <table class="metadata_table" style="margin-top: 1em;">
- <tr><th>Title</th><td>${item.title}</td></tr>
- <tr><th>Type</th><td>${item.get_item_type_display()}</td></tr>
- <tr py:if="item.item_type=='PHYS'"
- py:with="avail, status = item.describe_physical_item_status()">
- <th>Status</th><td><div class="${avail and 'available' or 'unavailable'}">${status}</div></td>
- </tr>
- <tr py:if="smallint">
- <th>Small Number</th><td>${smallint}</td>
- </tr>
- <tr py:if="item.url"><th>URL</th><td><a href="${item.url}">${item.url}</a></td></tr>
- </table>
- <div py:if="item.item_type=='ELEC'">
- <h2 class="metadata_subhead">Attached document</h2>
- <table class="metadata_table">
- <tr><th>Content type</th><td>${item.fileobj_mimetype}</td></tr>
- <tr><th>Size</th><td>${item.fileobj.size} bytes</td></tr>
- <tr><th/><td><a class="bigdownload" href="${item.item_url()}">Download</a></td></tr>
- </table>
- </div>
- <div py:if="metadata">
- <h2 class="metadata_subhead">Additional metadata</h2>
- <table class="metadata_table">
- <tr py:for="attr in metadata">
- <th>${attr.get_name_display()}</th>
- <td py:if="attr.name != 'syrup:marc'">
- ${attr.value}
- </td>
- <td py:if="attr.name == 'syrup:marc'">
- <div id="marcdatashow"><a href="javascript:$('#marcdata').show();$('#marcdatashow').hide();void(0);">show</a></div>
- <div id="marcdata" style="display: none;">
- <?python dct = loads(attr.value); keys=dct.keys(); keys.sort() ?>
- <table>
- <tr py:for="k in keys">
- <th>${k}</th>
- <td>${dct[k]}</td>
- </tr>
- </table>
- </div>
- </td>
- </tr>
- </table>
- </div>
- </body>
-</html>
+++ /dev/null
-<?python
-title = 'Move item under a different heading'
-?>
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- xmlns:py="http://genshi.edgewall.org/">
- <xi:include href="master.xhtml"/>
- <xi:include href="components/course.xhtml"/>
- <head>
- <title>${title}</title>
- <script type="text/javascript" src="${ROOT}/static/menublocks.js"/>
- </head>
- <body>
- ${course_banner(course)}
- ${nested_title(item)}
- <h2>${title}</h2>
- <p>Please choose the heading under which this item should be moved:</p>
- <form action="." method="POST">
- <table class="metadata_table">
- <tbody style="text-align: left;">
- <tr><th>Item title:</th><td>${item.title}</td></tr>
- <tr><th>Current heading:
- </th><td>${item.parent_heading and item.parent_heading.title or 'Top Level'}
- <div class="gap"/></td></tr>
- <tr><th>New heading:</th>
- <td>
- ${heading_tree(course.item_tree(), stop_at=item)}
- <div class="gap"/>
- </td>
- </tr>
- <tr>
- <th/>
- <td><input type="submit" value="Move item"/></td>
- </tr>
- </tbody>
- </table>
- </form>
- </body>
-</html>