Диссертация (1167217), страница 61
Текст из файла (страница 61)
filesizeis about 200KB')db.page.created_by.readable = db.page.created_by.writable = Falsedb.page.created_on.readable = db.page.created_on.writable = Falsedb.post.body.requires = IS_NOT_EMPTY()db.post.page_id.readable = db.post.page_id.writable = Falsedb.post.created_by.readable = db.post.created_by.writable = Falsedb.post.created_on.readable = db.post.created_on.writable = Falsedb.document.name.requires = IS_NOT_IN_DB(db, 'document.name')db.document.page_id.readable = db.document.page_id.writable = Falsedb.document.created_by.readable = db.document.created_by.writable = Falsedb.document.created_on.readable = db.document.created_on.writable = False## configure auth policyauth.settings.registration_requires_verification = Falseauth.settings.registration_requires_approval = Trueauth.settings.reset_password_requires_verification = FalseТаблица авторизации расширена пользовательским соглашением.
Таблицастраниц имеет комментарий-инструкцию по использованию тэгов. Ограничениядлины кода страницы составляют 10−5000 символов, но легко могут бытьизменены. Размер прикрепляемого файла не может быть больше 200 кБ (этотпараметр также можно изменить), но количество прикрепляемых файлов неограничивается.Новыепользователиодобряютсяадминистраторомвеб-приложения вручную.Блок «представление» получит файлы create.html, documents.html, edit.html,search.html и show.html.
На главной странице index.html приводится алфавитный358список всех имеющихся статей в виде гиперссылок, а также гиперссылкиперехода на веб-страницы поиска и создания новой статьи, ее код состоит всегоиз нескольких строк:{{extend 'layout.html'}}<h1>Available wiki pages</h1>[ {{=A('search', _href=URL('search'))}} ]<br /><ul>{{for page in pages:}}{{=LI(A(page.title, _href=URL('show', args=page.id)))}}{{pass}}</ul>[ {{=A('create page', _href=URL('create'))}} ]Веб-страница создания новой статьи create.html еще менее наполненакодом:{{extend 'layout.html'}}<h1>Create new wiki page</h1>{{=form}}Кодвеб-страницыпоискаsearch.htmlтакжетолькоссылаетсянапеременные своей функции:{{extend 'layout.html'}}<h1>Search wiki pages</h1>[ {{=A('listall', _href=URL('index'))}}]<br />{{=form}}<br />{{=target_div}}Веб-страница просмотра содержит заголовок статьи, саму статью икомментарии.Гиперссылкадляредактированиядоступна,толькоеслипользователь определяется как автор статьи.
Файл show.html содержитзначительный код, состоящий в основном из вставок на языке программированияPython:{{extend 'layout.html'}}<h1>{{=page.title}}</h1><!-- три строки для разрешения видеть ссылку edit только автору статьи -->{{if db.auth_user[page.created_by].id == auth.user.id:}}[ {{=A('edit', _href=URL('edit', args=request.args))}} ]<br />{{pass}}<!--{{=MARKMIN(page.body)}}-->{{text=page.body}}{{if '*!*' in text:}}{{part=text.split('*!*')}}{{=XML(part[0])}}{{for i in range(1, len(part)):}}<!-- take a number between *!* and !!! in part[i] -->{{pos = part[i].find('!!!')}}{{num = ''}}{{for q in range(0, pos): num += part[i][q]}}<!-- check if such file is in db -->359{{if not db.document[num]:}}{{=B('[ no image with id %s in db]' % num)}}{{else:}}{{=IMG(_src=URL('download',args=db(db.document.id==num).select()[0]['file']))}}{{pass}}{{=XML(part[i][3+len(num):])}}{{pass}}{{else:}}{{=XML(text)}}{{pass}}<hr><h4>Comments</h4>{{for post in comments:}}<p>{{=db.auth_user[post.created_by].first_name + " " +db.auth_user[post.created_by].last_name}} on {{=post.created_on}}says <i>{{=post.body}}</i></p>{{pass}}<h4>Post a comment</h4>{{=form}}Почти все на этой веб-странице генерируется автоматически – она должнабыть универсальной для любой статьи, поэтому программа должна взять всюинформацию из базы данных.
Здесь реализуется авторский алгоритм вставкикартинок с помощью последовательности символов *!*n!!!, где n –идентификатор (id) в таблице прикрепленных файлов. Если файл с такимидентификатором не существует, то статья все равно отобразится, но вместокартинки будет выведено оповещение «no image with id n in db» (где n –запрашиваемый пользователем идентификатор). Веб-страница настроена так, чтонаписать хорошо оформленную статью можно только кодом HTML5, используянабор тэгов, который в начале может состоять всего из нескольких единиц(например, p, b, i, h1, h2, h3, универсальных атрибутов и пр.). Работа с кодомHTML при написании статьи не должна вызвать трудностей, наоборот – ее можнорассматривать как элемент, делающий авторство более увлекательным.Веб-страница редактированияedit.htmlпредставляет собойнемногорасширенную версию веб-страницы создания новой статьи. Она дополненагиперссылками на веб-страницы просмотра (show.html) и прикрепления файлов(documents.html):{{extend 'layout.html'}}<h1>Edit wiki page</h1>360[ {{=A('show', _href=URL('show', args=request.args))}}| {{=A('documents', _href=URL('documents', args=request.args))}} ]<br />{{=form}}Веб-страницаdocuments.htmlавтоматическивизуализируеттаблицуприкрепленных файлов базы данных.
Это позволяет сократить ее код донескольких строк, вне зависимости от размера отображаемой таблицы:{{extend 'layout.html'}}<h1>Documents for page: {{=page.title}}</h1>[ {{=A('show', _href=URL('show', args=request.args))}} ]<br /><h2>Documents</h2>{{=grid}}Блок «поведение» содержит функции веб-страниц в файле default.py.Приведем его код целиком:def index():""" this controller returns a dictionary rendered by the viewit lists all wiki pages>>> index().has_key('pages')True"""pages = db().select(db.page.id,db.page.title,orderby=db.page.title)return dict(pages=pages)@auth.requires_login()def create():"""creates a new empty wiki page"""form = SQLFORM(db.page).process(next=URL('index'))return dict(form=form)@auth.requires_login()def show():"""shows a wiki page"""this_page = db.page(request.args(0,cast=int)) or redirect(URL('index'))db.post.page_id.default = this_page.idform = SQLFORM(db.post).process()pagecomments = db(db.post.page_id==this_page.id).select()return dict(page=this_page, comments=pagecomments, form=form)@auth.requires_login()def edit():"""edit an existing wiki page"""this_page = db.page(request.args(0,cast=int)) or redirect(URL('index'))page=this_pageif db.auth_user[page.created_by].id == auth.user.id: # проверка,является ли текущей пользователь автором статьиform = SQLFORM(db.page, this_page).process(next =URL('show',args=request.args))else:redirect(URL('index'))return dict(form=form)@auth.requires_login()361def documents():"""browser, edit all documents attached to a certain page"""page = db.page(request.args(0,cast=int)) or redirect(URL('index'))if db.auth_user[page.created_by].id == auth.user.id: # проверка,является ли текущей пользователь автором статьиdb.document.page_id.default = page.iddb.document.page_id.writable = Falsegrid = SQLFORM.grid(db.document.page_id==page.id,args=[page.id])else:redirect(URL('index'))return dict(page=page, grid=grid)def user():return dict(form=auth())def download():"""allows downloading of documents"""return response.download(request, db)@auth.requires_login()def search():"""an ajax wiki search page"""return dict(form=FORM(INPUT(_id='keyword',_name='keyword',_onkeyup="ajax('callback', ['keyword'], 'target');")),target_div=DIV(_id='target'))def callback():"""an ajax callback that returns a <ul> of links to wiki pages"""query = db.page.title.contains(request.vars.keyword)pages = db(query).select(orderby=db.page.title)links = [A(p.title, _href=URL('show',args=p.id)) for p in pages]return UL(*links)service = Service()@service.xmlrpcdef find_by(keyword):"""finds pages that contain keyword for XML-RPC"""return db(db.page.title.contains(keyword)).select().as_list()def call():"""exposes all registered services, including XML-RPC"""return service()Элементарное веб-приложение wiki работает.
Можно модифицировать егопо собственному желанию, начиная с интерфейса, как самого простогокомпонента, и постепенно переходя к функциям в блоке «поведение».Организовать работу в wiki следует таким образом, чтобы каждыйобучающийся работал над своей собственной статьей. Комментировать статьюмогут все остальные участники, включая автора. Таким образом, комментарийпревращается в подобие форума, на котором участники предлагают авторуулучшить статью, а автор аргументировано отвечает на предложения. Оцениватьможно как саму статью, так и качество комментирования.362Приложение 2. Листинг программы texttogaps для преобразованиятекста в код упражнения с пропусками LMS Moodlef = open('texttogap.txt', 'r', encoding='UTF-8')text = f.read()f.close()""" {1:SHORTANSWER:%100%word#} """beg = "{1:SHORTANSWER:%100%"end = "#}"words = text.split(" ")newtext = ""for word in words:alfnum = Truefor ch in word:if not ch.isalpha():alfnum = Falseif alfnum:newtext += beg + word + end + " "else:newtext += word + " "print(newtext)363Приложение 3.
Листинг программы txttoxmlglossary дляпреобразования подготовленного текстового файла в файлглоссария LMS Moodlef = open("text.txt", "r", encoding="utf-8")text = f.readlines()f.close()xmlcode = """<?xml version="1.0" encoding="UTF-8"?><GLOSSARY><INFO>"""xmlcode += "<NAME>" + text[0][:-1] + """</NAME><INTRO></INTRO><INTROFORMAT>1</INTROFORMAT><ALLOWDUPLICATEDENTRIES>0</ALLOWDUPLICATEDENTRIES><DISPLAYFORMAT>entrylist</DISPLAYFORMAT><SHOWSPECIAL>1</SHOWSPECIAL><SHOWALPHABET>1</SHOWALPHABET><SHOWALL>1</SHOWALL><ALLOWCOMMENTS>0</ALLOWCOMMENTS><USEDYNALINK>1</USEDYNALINK><DEFAULTAPPROVAL>1</DEFAULTAPPROVAL><GLOBALGLOSSARY>0</GLOBALGLOSSARY><ENTBYPAGE>30</ENTBYPAGE><ENTRIES>\n"""for i in range(1, len(text)):if text[i] == "-\n":xmlcode += "<ENTRY>\n"xmlcode += "<CONCEPT>%s</CONCEPT>\n<DEFINITION>" % text[i+1][:-1]ii = i+2while text[ii] != "\n":xmlcode += "<p>" + text[ii][:-1] + "</p>"ii += 1xmlcode += """</DEFINITION>\n<FORMAT>1</FORMAT><USEDYNALINK>1</USEDYNALINK><CASESENSITIVE>1</CASESENSITIVE><FULLMATCH>1</FULLMATCH><TEACHERENTRY>1</TEACHERENTRY>\n<ALIASES>"""iii = ii + 1while text[iii] != "\n":xmlcode += "<ALIAS><NAME>" + text[iii][:-1] +"</NAME></ALIAS>\n"iii += 1xmlcode += "</ALIASES>\n</ENTRY>\n"xmlcode += """</ENTRIES></INFO></GLOSSARY>"""f = open("glossary.xml", "w", encoding="utf-8")f.write(xmlcode)f.close()364Приложение 4.
Листинг программы xmltoline для преобразованияглоссария LMS Moodle в строку для тренажера вокабуляраimport refrom xml.dom import minidomxmldoc = minidom.parse('Вокабуляр.xml')conceptlist = xmldoc.getElementsByTagName('CONCEPT')deflist = xmldoc.getElementsByTagName('DEFINITION')line = ""for i in range(len(conceptlist)):line += '"' + conceptlist[i].childNodes[0].data + " || " +deflist[i].childNodes[0].data + '",'line = line.replace("<p>", "\n")line = line.replace("<br />", "\n")line = re.sub('<[^<]+?>', '', line)line = line.replace("\n\n", " | ")line = line.replace("\n", " | ")print(line[:-1])365Приложение 5.