#!/usr/bin/env python
# -*- coding: utf-8 -*-
# TOMUSS: The Online Multi User Simple Spreadsheet
# Copyright (C) 2008-2014 Thierry EXCOFFIER, Universite Claude Bernard
#
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Contact: Thierry.EXCOFFIER@bat710.univ-lyon1.fr
"""
If there is a ':' before the login name then the APOGEE link is
translated as an IFRAME to include all the information.
"""
import os
import time
import cgi
import collections
from .. import plugin
from .. import configuration
from .. import inscrits
from .. import referent
from .. import utilities
from .. import tablestat
from .. import abj
from .. import document
from .. import column
from .. import teacher
from .. import files
from .. import signature
files.add('PLUGINS', 'suivi_student.css')
files.add('PLUGINS', 'suivi_student.js')
last_full_read_time = 0
def dir_mtime(year, semester):
name = os.path.join(configuration.db, "Y%s" % year, "S" + semester)
return os.path.getmtime(name)
def update_the_ues(year, semester):
"""Reread all thes ues"""
global last_full_read_time
if (tuple(configuration.year_semester) == (year, semester)
or tuple(configuration.year_semester_next) == (year, semester)):
dt = 60
else:
dt = 3600
mtime = dir_mtime(year, semester)
if configuration.regtest or mtime - last_full_read_time > dt:
last_full_read_time = mtime
# Force the generator to do its job to check new students or tables
tuple(tablestat.les_ues(year, semester, true_file=False))
def the_ues(year, semester, login):
if not configuration.index_are_computed:
update_the_ues(year, semester)
login = utilities.the_login(login)
tables = []
if document.tables_of_student:
student_tables = document.tables_of_student.get(login,[])
else:
table_list = document.update_index(login)
if table_list is None:
return ()
student_tables = [document.table(*t, ro=True, create=False)
for t in set(table_list) # Remove duplicates
if t[0] == year and t[1] == semester
]
# Remove UE indexed but no more on disc
student_tables = [t
for t in student_tables
if t
]
now = time.time()
for t in student_tables:
t.rtime = now
return [t
for t in student_tables
if t.official_ue
]
for ue in student_tables:
tables.append(document.table(year, semester, ue, ro=True))
return tables
def teacher_can_see_suivi(server, the_student):
prefs = display_preferences_get(the_student)
priv = bool(prefs.get('private_suivi', False))
if server.ticket.user_name == the_student:
return priv, True
if configuration.is_member_of(server.ticket.user_name,
('grp:see_private_suivi',)):
return priv, True
# The current referent only, not the old ones
year, semester = configuration.year_semester
if referent.referent(year, semester, the_student)==server.ticket.user_name:
return priv, True
local = configuration.visible_from_suivi(server, the_student)
if local is not None:
return priv, local
if not priv:
return priv, True
for t in the_ues(server.year, server.semester, the_student):
if server.ticket.user_name in t.masters:
return priv, True
# Anybody who enter a grade
for line in t.get_lines(the_student):
for cell in line:
if cell.author == server.ticket.user_name:
return priv, True
return priv, False
def display_referent(server):
ref = referent.referent(server.year, server.semester, server.suivi_login)
if ref:
return list(inscrits.L_fast.firstname_and_surname_and_mail(ref))+[0,ref]
return [0, 0, 0, referent.need_a_referent(server.suivi_login), ref]
def display_copyright(server):
return configuration.version
def display_mails(server):
if server.is_a_student:
return '' # Student can't see all teacher mail addresses
teachers = collections.defaultdict(list)
for t in the_ues(server.year, server.semester, server.suivi_login):
if tuple(t.get_items(server.suivi_login)):
for teacher_login in t.masters:
teachers[teacher_login].append(t.ue)
if not teachers:
return '' # No teachers
return [' '.join(v) + ' <' + str(inscrits.L_fast.mail(k)) + '>'
for k, v in teachers.items()
]
def display_names(server):
return inscrits.L_fast.firstname_and_surname_and_mail(server.suivi_login)
def display_login(server):
return server.suivi_login
def display_charte(server):
if not referent.need_a_charte(server.suivi_login):
return ''
return utilities.charte_signed(server.suivi_login, server)
def display_signature(server):
if not server.suivi_question.html_answered():
return '' # No message/contract link
def display_logo(server):
return configuration.logo
def display_semesters(server):
t = {}
for (url, dummy_port, year, semester, dummy_host
) in configuration.suivi.urls.values():
if configuration.display_this_semester_to_the_student(
year, semester, server.suivi_login):
t['%d/%s' % (year, semester)] = url
return t
def display_get_student(server):
if server.ticket.is_a_referent:
return True
return ''
def display_referent_notepad(server):
if not server.suivi_ref:
return ''
if server.suivi_ref != server.ticket.user_name:
return ''
if server.is_a_student:
return '' # Student view
tyear = utilities.university_year()
s = []
while True:
table = document.table(tyear, 'Referents',
utilities.login_to_module(server.suivi_ref),
ro=True, create=False)
if table is None:
break
s.append(table.referent_resume(table, server.suivi_login))
tyear -= 1
return '\n'.join(s)
def display_question(server):
return getattr(server, 'suivi_question_html', '')
def display_message(dummy_server):
return configuration.suivi_student_message
def display_abjs(server):
return [
(from_date, to_date, comment)
for from_date, to_date, dummy_author, comment in server.suivi_abj.abjs
]
def display_da(server):
return [
(from_date, to_date, comment)
for from_date, to_date, dummy_author, comment in server.suivi_abj.da
]
def display_rss(server):
if server.is_a_student:
if server.ticket.user_name == server.suivi_login:
return utilities.manage_key('LOGINS', os.path.join(
server.suivi_login,'rsskey'))
else:
return "fake_RSS_key"
return ''
def display_tt(server):
table = document.table(utilities.university_year(), 'Dossiers', 'tt',
ro=True)
tt = abj.tierstemps(server.suivi_login, table_tt=table)
if tt:
return tt
else:
return ''
def display_more_on_suivi(server):
return configuration.more_on_suivi(server.suivi_login, server)
def display_member_of(server):
if server.is_a_student:
return ''
member_of = list(inscrits.L_fast.member_of_list(server.suivi_login))
member_of.sort()
member_of = [
unicode(i, configuration.ldap_encoding)
.replace(',DC=univ-lyon1,DC=fr','')
for i in member_of
]
etapes = []
for etape in inscrits.L_fast.etapes_of_student(server.suivi_login):
e = teacher.all_ues().get('etape-' + etape)
if e:
title = e.intitule().encode('utf-8')
else:
title = "???"
etapes.append([etape, title])
return member_of, etapes
def json(server, table, line, line_id):
table_attrs = {}
for attr in column.TableAttr.attrs.values():
if attr.name == 'formation': # XXX
continue
if attr.computed:
continue
if attr.gui_display == 'GUI_a':
continue
value = getattr(table, attr.name, attr.get_default_value(table))
if value == '' or value == 0 or value == () or value == []:
continue
table_attrs[attr.name] = value
table_attrs['masters'] = [
inscrits.L_fast.firstname_and_surname_and_mail(login)
for login in table.masters]
table_attrs['ue'] = table.ue
table_attrs['year'] = table.year
table_attrs['semester'] = table.semester
table_attrs['columns'] = table.columns.js(
hide = server.is_a_student and 1 or True,
python = True)
table_attrs['line_id'] = line_id
table_attrs['line'] = line.json(for_student=server.is_a_student,
columns = table.columns)
table_attrs['stats'] = table.lines.line_stat(
table, line, link=not server.is_a_student)
return table_attrs
def display_grades(server):
ss = []
s = []
codes = {}
for t in the_ues(server.year, server.semester, server.suivi_login):
for line_id, line in t.get_items(server.suivi_login):
ss.append(json(server, t, line, line_id))
if ss[-1]:
# A line has been displayed
codes[t.ue_code] = True
if (configuration.suivi_display_more_ue
and (server.year, server.semester) == configuration.year_semester
and (not server.is_a_student or configuration.suivi_check_student_lists(server.suivi_login))
):
for t in inscrits.L_fast.ues_of_a_student_short(server.suivi_login):
if '-' not in t:
continue
title = teacher.all_ues().get(t.split('-')[1])
if title:
title = title.intitule()
else:
title = ''
if t not in codes:
s.append((t, title))
ss.sort()
return [ss, s]
def display_students(server):
students = referent.students_of_a_teacher(server.suivi_login)
if not students:
return ''
return [[student] + inscrits.L_slow.get_student_info(student)
for student in students
]
def display_preferences_get(login):
prefs = utilities.manage_key('LOGINS', os.path.join(login, 'preferences'))
if prefs:
return eval(prefs)
else:
return {}
def display_preferences(server):
if server.is_a_student:
login = server.suivi_login
else:
login = server.ticket.user_name
prefs = display_preferences_get(login)
if not prefs:
if server.is_a_student:
prefs = {}
else:
prefs = {'highlight_grade': 1}
for k in ('show_empty', 'color_value', 'highlight_grade', 'private_suivi',
'hide_right_column', 'big_text', 'hide_picture',
'no_teacher_color', 'big_box', 'recursive_formula'):
if k not in prefs:
prefs[k] = 0
# XXX For old files from TOMUSS before 5.3.2
priv = utilities.manage_key('LOGINS', os.path.join(login, 'private'))
if priv and priv.startswith('1'):
prefs['private_suivi'] = 1
if not configuration.suivi_student_allow_private or not server.is_a_student:
del prefs['private_suivi']
return prefs
from .. import display
D = display.Display
# Standard suivi page
D('Top' , [] ,0, js='Vertical')
D('Private' , [] ,0, js='Vertical')# Minimal suivi page if private
D('Question' , [] ,0, js='Vertical')# Minimal suivi page if ask
D('User' ,['Top','Private','Question'],-3, js='Horizontal')
D('Preamble' ,['Top','Private','Question'],-2)
D('Message' ,'Top' ,-1, js="Horizontal", data=display_message)
D('Messages' ,'Top' ,-0.5) # To one student only
D('Body' ,'Top' ,1, js='Horizontal')
D('BodyLeft' , 'Body' ,0, js='Vertical')
D('RightClip' , 'Body' ,1)
D('BodyRight' , 'RightClip' ,0, js='Vertical')
D('TopLine' ,['BodyLeft', 'Private','Question'],0, js="Horizontal")
D('Student' ,['BodyLeft', 'Private','Question'],1, js='Horizontal')
D('ReferentNP' , 'BodyLeft' ,2, js='Horizontal',data=display_referent_notepad)
D('LastGrades' , 'BodyLeft' ,3)
D('Grades' , 'BodyLeft' ,4, data=display_grades)
D('Students' , 'BodyLeft' ,5, data=display_students)
D('Semesters' , 'BodyRight' ,1, data=display_semesters)
D('LinksTable' , 'BodyRight' ,2)
D('Abjs' , 'BodyRight' ,3, data=display_abjs)
D('DA' , 'BodyRight' ,4, data=display_da)
D('TT' , 'BodyRight' ,5, data=display_tt)
D('MoreOnSuivi' , 'BodyRight' ,9, data=display_more_on_suivi)
D('Logo' , 'User' ,0, data=display_logo)
D('Reload' , 'User' ,2)
D('Profiling' , 'User' ,3)
D('IdentityR' , 'User' ,-1, js='Horizontal') # Yes : -1
D('Logout' , 'IdentityR' ,-1)
D('Explanation' , 'IdentityR' ,0, data=display_copyright)
D('Preferences' , 'IdentityR' ,1, data=display_preferences)
D('IsPrivate' , 'Private' ,5, data=display_referent)
D('AskQuestion' , 'Question' ,6, data=display_question)
D('Picture' , 'TopLine' ,0)
D('Login' , 'TopLine' ,1, js='Vertical', data=display_login)
D('Names' , 'TopLine' ,2, data=display_names)
D('GetStudent' , 'TopLine' ,3, data=display_get_student)
# Line 1 for students and 1&2 fr teachers :
D('Referent' , 'LinksTable',0, data=display_referent)
D('Mails' , 'LinksTable',1, data=display_mails)
D('Official' , 'LinksTable',2)
D('Bilan' , 'LinksTable',3, data=display_get_student)
# Line 3 for teachers
D('StudentView' , 'LinksTable',4)
D('NewSignature', 'LinksTable',5)
# Line 4
D('Charte' , 'LinksTable',6, display_charte)
D('Signature' , 'LinksTable',7, display_signature)
D('RSS' , 'LinksTable',8, data=display_rss)
D('MemberOf' , 'LinksTable',10, data=display_member_of)
# Template of an UE
D('UE' , [] ,0)
D('UEHeader' , 'UE' ,0, js='Horizontal')
D('UEComment' , 'UE' ,1)
D('UEGrades' , 'UE' ,2)
D('UETitle' , 'UEHeader' ,0)
D('UEMasters' , 'UEHeader' ,1)
# Template of a Cell
D('Cell' , [] ,0, js='Vertical')
D('CellTop' , 'Cell' ,0, js='Vertical')
D('CellBox' , 'Cell' ,1)
D('CellBottom' , 'Cell' ,2, js='Vertical')
D('CellAuthorLine', 'CellBottom',0, js='Horizontal')
D('CellColumn' , 'CellBottom',2)
D('CellComment' , 'CellBottom',1)
D('CellAuthor' , 'CellAuthorLine',0)
D('CellMTime' , 'CellAuthorLine',1)
D('CellTitle' , 'CellBox' ,0)
D('CellValue' , 'CellBox' ,1)
D('CellTypeLine', 'CellTop' ,0, js='Horizontal')
D('CellDate' , 'CellTop' ,1)
D('CellStatLine', 'CellTop' ,2, js='Horizontal')
D('CellRank' , 'CellStatLine',0)
D('CellAvg' , 'CellStatLine',1)
D('CellType' , 'CellTypeLine' ,0)
D('CellFormula' , 'CellTypeLine' ,1)
def student_statistics(login, server, is_a_student=False, expand=False,
is_a_referent=False):
utilities.warn('Start', what='table')
server.is_a_student = is_a_student
server.suivi_login = login
server.suivi_question = signature.get_state(login)
server.suivi_ref = referent.referent(server.year, server.semester, login)
server.suivi_abj = abj.Abj(server.year,server.semester, server.suivi_login)
server.suivi_private_life, visible = teacher_can_see_suivi(server, login)
if not visible:
return display.data_to_display(server, 'Private')
if is_a_student:
server.suivi_question_html = server.suivi_question.html()
if server.suivi_question_html:
return display.data_to_display(server, 'Question')
return display.data_to_display(server, 'Top')
def page_tail(server):
# Not in JS in case of multiple students on the same page
server.the_file.write('<br class="noprint">'*10) # for popups
def student(server, login=''):
"""Display all the informations about a student."""
if not login:
login = server.ticket.user_name
suivi_headers(server, is_student=True)
student_statistics(login, server, True)
page_tail(server)
plugin.Plugin('student', '/{*}', function=student, group='!staff',
launch_thread=True, unsafe=False,
password_ok = None)
def accept(server):
"""The student signs the contract"""
suivi_headers(server, is_student=True)
server.the_file.write('<img src="%s/=%s/store_accept">' % (
configuration.server_url, server.ticket.ticket)
)
student_statistics(server.ticket.user_name, server, True)
page_tail(server)
plugin.Plugin('accept', '/accept', function=accept, group='!staff',
launch_thread=True,
password_ok = None)
def suivi_headers(server, is_student=True):
server.the_file.write(
str(document.the_head)
+ '''<link rel="stylesheet" href="%s/suivi_student.css" type="text/css">
<script src="%s/suivi_student.js" onload="this.onloadDone=true;"></script>
''' % (configuration.url_files, configuration.url_files)
+ document.translations_init(server.ticket.language)
)
server.the_file.flush()
server.the_file.write(
'<noscript><h1>'+server._('MSG_need_javascript')+'</h1></noscript>\n'
+ "<script>"
+ 'var table_attr = {} ;'
+ "var semester = %s;\n" % utilities.js(server.semester )
+ "var year = %s;\n" % utilities.js(server.year )
+ "var ticket = %s;\n" % utilities.js(server.ticket.ticket )
+ "var username = %s;\n" % utilities.js(server.ticket.user_name )
+ "var admin = %s;\n" % utilities.js(configuration.maintainer)
+ "var is_a_teacher = %s;\n" % int(not is_student)
+ "var url = %s;\n" % utilities.js(configuration.server_url)
+ "var url_suivi = %s;\n" % utilities.js(utilities.StaticFile._url_)
+ "var url_files = %s ;\n" % utilities.js(configuration.url_files)
+ "var root = %s ;\n" % utilities.js(list(configuration.root))
+ "var maintainer = %s;\n" % utilities.js(configuration.maintainer)
+ 'var max_visibility_date = %d;\n' % configuration.max_visibility_date
+ 'var bilan_des_notes = %s ; \n' % utilities.js(
configuration.bilan_des_notes)
+ "</script>\n"
+ "</head>\n"
+ '<body class="%s">\n' % server.semester
+ '<div id="top"></div>'
+ '<script>\n'
+ utilities.wait_scripts()
+ 'function initialize_suivi()'
+ '{ if ( ! wait_scripts("initialize_suivi()") ) return ;'
+ 'initialize_suivi_real() ; }'
+ 'initialize_suivi();\n'
+ '</script>\n'
)
def home(server, nothing_behind=True):
"""Display the home page for 'suivi', it asks the student id."""
suivi_headers(server, is_student=nothing_behind)
server.teacher_as_a_student = True
if nothing_behind:
student_statistics(server.ticket.user_name, server, is_a_student=True)
page_tail(server)
plugin.Plugin('home', '/', group='staff', function = home, unsafe=False)
def modified_tables(server, login):
"""This function is currently unused
It search all the modified tables
"""
for t in tablestat.les_ues(server.year, server.semester, true_file=True):
for line in t.lines.values():
if t not in tables:
for v in line:
if v.author == login:
url = ('<a href="%s/=' % configuration.server_url +
ticket.ticket + '/' +
str(t.year) + '/' + str(t.semester) + '/' +
t.ue + '/=full_filter=@' + login +
'" target="_blank">' +
t.location() + '</a>'
)
tables[t] = tablestat.TableStat(url)
break
for t in tables:
for line in t.lines.values():
for v in line:
if v.author == login:
tables[t].update(v)
if tables:
s += ("<p>" + server._("MSG_suivi_student_ue_changes") % (
sum([v.nr for v in tables.values()]),
len(tables)) +
'\n'.join(['''
<TABLE class="colored"><tr>
<th><script>Write("TH_suivi_student_ue");</script></th>
<th><script>Write("TH_suivi_student_nr_grades");</script></th>
<th><script>Write("TH_suivi_student_first_change");</script></th>
<th><script>Write("TH_suivi_student_last_change");</script></th></tr>
'''] +
[ str(t) for t in tables.values()] +
['</TABLE>']))
def page_suivi(server):
"""Display the informations about all the students indicated."""
if (len(server.the_path) == 0
or server.the_path[0] == ''
or server.the_path[0] == server.ticket.user_name):
server.teacher_as_a_student = True
student(server)
return
server.the_path[0] = server.the_path[0].replace('?X=', '').replace('?=','')
if server.the_path[0].startswith(' '):
# If student id starts by space the teacher want
# to see exactly the same thing than the student
student(server, server.the_path[0][1:])
return
if server.the_path[0].startswith(':'):
# Expand more information in resume.
server.the_path[0] = server.the_path[0][1:]
expand = True
else:
expand = False
home(server, nothing_behind=False)
logins = server.the_path[0].replace('+',',').strip(',').split(',')
logins = [inscrits.safe(lo).lower() for lo in logins]
server.the_file.write(
'<title>' +
', '.join([inscrits.L_fast.firstname_and_surname(login)[0].title() +
' ' + inscrits.L_fast.firstname_and_surname(login)[1]
for login in logins]).encode('utf8') +
'</title>'
)
for login in logins:
try:
login = utilities.the_login(login)
student_statistics(login, server, is_a_student=False,expand=expand)
except ValueError:
raise
server.the_file.flush()
page_tail(server)
plugin.Plugin('infos', '/{*}', group='staff', password_ok = None,
function = page_suivi, unsafe=False,
launch_thread=True,
)
def escape(t):
return unicode(t,'utf-8').replace('>', u'\ufe65').replace('<', u'\ufe64').replace('&','&').encode('utf-8')
def rss_author(x):
try:
fn, sn = inscrits.L_fast.firstname_and_surname(x)
fn = fn.encode('utf8')
sn = sn.encode('utf8')
return inscrits.L_fast.mail(x) + ' (%s %s)' % (fn.title(), sn.upper())
except:
return x
def rss_date(date=None):
if date is None:
date = time.localtime(time.time())
elif isinstance(date, str):
date = time.strptime(date, '%Y%m%d%H%M%S')
return time.strftime('%a, %d %b %Y %H:%M:%S +0000', date)
def page_rss(server):
"""RSS for the student."""
if len(server.the_path) != 1:
login = False
else:
login = utilities.manage_key('RSSLOGINS', server.the_path[0],
separation=2)
if login is False:
server.the_file.write('''<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<language>fr</language>
<title>TOMUSS</title>
<description>%s</description>
<lastBuildDate>%s</lastBuildDate>
<link></link>
<item><title>%s</title>
<description>%s</description>
<link>%s</link>
</item>
</channel>
</rss>
''' % ( utilities._("MSG_suivi_student_RSS_title"),
time.asctime(),
utilities._("MSG_suivi_student_RSS_forbiden_title"),
utilities._("MSG_suivi_student_RSS_forbiden_description"),
utilities.StaticFile._url_))
return
server.the_file.write('''<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<language>fr</language>
<title>TOMUSS %s</title>
<description>%s</description>
<lastBuildDate>%s</lastBuildDate>
<link>%s</link>''' % ( login,
utilities._("MSG_suivi_student_RSS_title"),
rss_date(), utilities.StaticFile._url_))
s = []
# Do not display change newer than ONE hour.
if configuration.regtest:
limit = '9999' # The regtests want to see all
else:
limit = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time() - 3600))
for t in the_ues(server.year, server.semester, login):
for line in t.get_lines(login):
for cell,column in zip(line[6:], t.columns[6:]):
if cell.date > limit:
continue
if cell.value == '':
continue
if not column.visible():
continue # Hidden column
if column.type.cell_compute == 'undefined':
s.append((cell.date, cell, t, column))
s.sort()
for date, cell, table, column in s[-10:]:
if cell.comment:
comment= cgi.escape(utilities._("MSG_suivi_student_RSS_value_comment")
+ '<b>') + escape(cell.comment) + cgi.escape('</b>,<br>')
else:
comment = ''
if column.comment:
column_comment = utilities._("MSG_suivi_student_RSS_column_comment"
) + '«' + \
escape(column.title) + cgi.escape('» : <b>') + escape(
column.comment) + cgi.escape('</b>,<br>')
else:
column_comment = ''
if column.type.name == 'Note':
note_range = column.type.value_range(*column.min_max())
else:
note_range = ''
table_title = escape(table.table_title)
if table.comment:
table_title += ' (<b>' + escape(table.comment) + '</b>)'
table_title = cgi.escape(table_title + ',<br>')
server.the_file.write(
'<item>\n' +
'<title>%s : %s : %s%s</title>\n' % (table.ue,
escape(column.title),
escape(str(cell.value)),
note_range) +
'<description>%s%s%s%s</description>\n' % (
table_title,
column_comment,
comment,
cgi.escape(utilities._("MSG_suivi_student_RSS_value_modified")
+ '<b>' + cell.author
+ '</b>,<br>' + utilities.nice_date(cell.date)
+ '<br>')
) +
'<link>%s</link>' % utilities.StaticFile._url_ +
'<author>%s</author>\n' % rss_author(cell.author) +
'<pubDate>%s</pubDate>\n' % rss_date(document.date_time(date))+
'<guid isPermaLink="false">%s %s</guid>\n' % (table.ue,
column.the_id) +
'</item>\n')
server.the_file.write('''
</channel>
</rss>
''')
plugin.Plugin('rss', '/rss/{*}', authenticated=False, password_ok = None,
function = page_rss,
launch_thread=False,
mimetype = 'application/rss+xml',
)
def page_rss2(server):
"""RSS for the table."""
link = '%s/%s/%s/%s' % (configuration.server_url,
server.year,
server.semester,
server.the_path[0]
)
server.the_file.write('''<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>TOMUSS : %s</title>
<description>%s</description>
<lastBuildDate>%s</lastBuildDate>
<link>%s</link>
''' % (server.the_path[0], utilities._("MSG_suivi_student_RSS_value_modified"),
rss_date(), link))
t = document.table(server.year, server.semester, server.the_path[0],
ro=True, create=False)
if t is None:
return
# Only the 10 most recents pages containing modifications
for p in [i for i in t.pages[1:] if i.request > 0 and i.date][-10:]:
date = p.date_time()
d = utilities._("MSG_suivi_student_RSS_table") % (
utilities.nice_date(p.date),
p.request,
)
t1 = p.day().replace('/', '$2F')
# %3C %3E to not broke XML syntax
# $20 $3F to not be tampered
f = '/=full_filter=@%s$20$3F%%3C_E%s$20$3F%%3E_E%s' % (
p.user_name, t1, t1)
server.the_file.write(
'<item>\n' +
'<title>%d modifications par %s</title>\n' % (p.request, p.user_name) +
'<description>%s</description>\n' % cgi.escape(d) +
'<link>%s%s</link>\n' % (link, f) +
'<pubDate>%s</pubDate>\n' % rss_date(date)+
'<author>%s</author>\n' % rss_author(p.user_name) +
'<guid isPermaLink="false">%d</guid>\n' % t.pages.index(p) +
'</item>\n'
)
server.the_file.write('''
</channel>
</rss>
''')
plugin.Plugin('rss2', '/rss2/{*}', authenticated=False, password_ok = None,
function = page_rss2,
launch_thread=False,
mimetype = 'application/rss+xml',
)