Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Федеральное государственное бюджетное образовательное учреждение
высшего профессионального образования
«КУБАНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ»
(ФГБОУ ВПО «КубГУ»)
Физико-технический факультет
Кафедра теоретической физики и компьютерных технологий
Допустить к защите в ГАК
_____ . ____ . 2013 г.
Заведующий кафедрой
д-р физ. мат. наук, профессор
_______________Е. Н. Тумаев
ДИПЛОМНАЯ РАБОТА
СОЗДАНИЕ СИСТЕМЫ МОНИТОРИНГА УРОВНЯ ЗНАНИЙ
Работу выполнил Елькин Михаил Николаевич
Специальность 230201 Информационные системы и технологии
Научный руководитель Значко В.Н.
Нормоконтролер
канд. физ.-мат. наук, доцент А. А. Мартынов
Краснодар 2013
РЕФЕРАТ
Елькин М.Н. СОЗДАНИЕ СИСТЕМЫ МОНИТОРИНГА УРОВНЯ ЗНАНИЙ. Дипломная работа: 32 с., 11 рис., 13 источников, 1 приложение.
СИСТЕМЫ СОЗДАНИЯ И ПРОХОЖДЕНИЯ ТЕСТОВ, СИСТЕМЫ УПРАВЛЕНИЯ БАЗАМИ ДАННЫХ, WEB-СЕРВЕР
Объектом разработки дипломной работы является система, предназначенная для сбора данных о результатах тестирования, состоящая из модулей создания и прохождения тестов, модуля назначения и модуля просмотра статистики.
Целью работы является разработка системы, способной хранить и обрабатывать большие объемы статистических данных с результатами тестов.
В результате выполнения дипломной работы спроектирована и разработана база данных для хранения статистики. Так же разработаны модули прохождения и создания тестов, и модуль просмотра статистических данных по результатам тестирования.
Содержание
[1]
[2] [2.1] 1.1 Постановка задачи [2.2] 1.2 Анализ существующих решений [2.2.1] 1.2.1 UniTest System 4 [2.2.2] 1.2.2 MyTest [2.2.3] 1.2.3 Moodle [2.3] 1.3 Требования к создаваемой системе [3] 2. Выбор и обоснование решения [3.1] 2.1 Описание общей архитектуры системы
[4] [4.1] 3.1 Конвенции программирования для системы [4.2] 3.2 Конвенции разработки Firebird [4.3] 3.3 Конвенции разработки ZOPE [4.4] 3.4 Описание архитектуры базы [4.5] 3.5 Методы разработки веб-интерфейсов [4.6] 3.6 Обработка данных при помощи python скриптов [4.7] 3.7 Создание хранимых процедур в Firebid
[5] [5.1] 4.1 Модуль создания тестов [5.2] 4.2 Модуль прохождения тестов [5.3] 4.3 Модуль назначения тестов [5.4] 4.4 Модуль просмотра статистики
[6]
[7]
[8] |
Системы, используемые для создания и прохождения тестов, обладают отличными инструментами для создания и прохождения созданных тестов. Но сбор статистики в таких системах является дополнительным функционалом, возможности которого не развиваются. Работа направлена на создание системы для сбора и дальнейшего анализа результатов тестирований. Использование системы позволит получать расширенные наборы статистических данных, и применять к ним методы системного анализа.
Работа содержит описание и анализ существующих систем для мониторинга уровня знаний. Так же в работе присутствует обоснование архитектурного решения, для разрабатываемой системы, и само решение, краткое описание инструментов разработки. В работе описана структура приложения, а так же основные приемы программирования используемые при реализации системы.
Сейчас существует множество программ для создания и прохождения тестов, но большинство из них не обладает полноценными инструментами по сбору, хранению, и обработке статистики, полученной при прохождении тестов.
Создание системы мониторинга уровня знаний позволит собирать подробную статистику по результатам тестирований студентов за длительный период. Помимо основных статистических данных, таких как результат тестирования и время затраченное на прохождение теста, система будет содержать данные, о времени ответа на каждый вопрос, средние баллы получаемые за тест и процент правильных ответов на вопрос. Все вопросы и тесты в базе будут разбиты по тематике, что позволит при анализе результатов эффективно выделять темы с которыми у учащихся возникают проблемы. При использовании такой системы длительное время на основе собранных ею данных, можно проводить анализ уровня подготовки студентов разных годов выпуска.
Система состоит из четырех основных модулей.
Сейчас на рынке программного обеспечения существует множество программных продуктов для мониторинга уровня знаний с различной архитектурой и сферой применения. Для анализа выберем три наиболее распространенные системы, такие как UniTest System 4, MyTest, Moodle. И подробнее познакомимся с этими системами.
UniTest System 4 решение для создания компьютерных тестов, проведения тестирования (как локально, так и по сети), детального анализа результатов тестирований и составления отчетов.
Система состоит из нескольких утилит Editor, Monitor, Report, Setting, Test.
Утилита Editor предназначен для создания и редактирования тестов, используемых для проведения тестирований в утилите Test. [1]
Утилита Test предназначена для прохождения тестов в созданных через утилиту Editor.
Утилита Report служит для получения информации по тестам, на рисунке 1 показан пример отчета созданного через Reporter
Утилита Monitor предназначен для администрирования и мониторинга процесса тестирования в сетевой версии пакета. В сетевой версии утилиты Test являются клиентами, которые подключаются к утилите Monitor и через нее проводят тестирование. Monitor контролирует все действия Test'ов и может разрешать или запрещать подключение отдельных клиентов (Test'ов) или целых групп, отключать или блокировать подключение уже подключенных клиентов. По каждому подключенному клиенту можно посмотреть подробную информацию (статус подключения, информация о тестируемом и о состоянии тестирования на текущий момент).
Settings позволяют настроить работу пакета UniTest System в целом и его отдельных компонентов. Можно установить пути к базам данных собст, используемым по умолчанию, и указать пароли к ним. Можно задать поля ввода данных о тестируемом, которые будут отображаться при тестировании. Здесь же можно настроить разбалловку тестов и внешний вид Test. [1]
Недостатком системы является хранение данных бинарном файле, что замедляет доступ к ним при работе с большими объемами данных, также это делает невозможным получение группированных по различным параметрам данных. Так же недостатком является отсутствие целостности статистики. Каждый запущенный модуль Monitor пишет информацию в свой отдельный файл, который в дальнейшем придется компоновать с другими файлами результатов, для получения целостной картины. В противном случае это означает, что модуль Monitor одновременно может быть запущен только на одном компьютере и что только один человек сможет быть администратором.
Рисунок 1 - Пример созданного отчета в системе
UniTest System через модуль Reporter
MyTest система программ для создания и проведения компьютерного тестирования, сбора и анализа их результатов, аналогичная UniTest System 4 состоит из трех модулей: Модуль тестирования (MyTestStudent), Редактор тестов (MyTestEditor) и Журнал тестирования (MyTestServer).
Редактор тестов (MyTestEditor) модуль для создания и редактирования тестов, для каждого теста создается бинарный файл
Модуль тестирования (MyTestStudent) предназначен для работы с бинарными файлами, созданными в редакторе тестов.
Журнал тестирования (MyTestServer) модуль программы MyTest, позволяющий централизовано принимать и обрабатывать результаты тестирования, раздавать тесты посредством компьютерной сети. Для отправки и получения результатов, отправки файлов с тестами используется протокол Интернета TCP/IP. На рисунке 2 форма для просмотра результатов в журнале тестирования MyTestServer.
Недостатком системы является хранение данных бинарном файле, что замедляет доступ к ним при работе с большими объемами данных, также это делает невозможным получение группированных по различным параметрам данных. Так же недостатком является отсутствие целостности статистики. Каждый запущенный модуль Monitor пишет информацию в свой отдельный файл, который в дальнейшем придется компоновать с другими файлами результатов, для получения целостной картины. В противном случае это означает, что модуль Monitor одновременно может быть запущен только на одном компьютере и что только один человек сможет быть администратором.
Рисунок 2 - Результаты тестов в MyTestServer.
Moodle система управления курсами (электронное обучение), также известная как система управления обучением или виртуальная обучающая среда. Представляет собой свободное (распространяющееся по лицензии GNU GPL) веб-приложение, предоставляющее возможность создавать сайты для онлайн-обучения. [7]
В Moodle так же есть возможность создавать тесты и получать статистику. При прохождении тестов статистика пишется в подключенную СУБД, но записываются не весь набор данных, который нас интересует. Так же у Moodle сложный, относительно других рассмотренных систем, процесс создания тестов. На рисунке 3 изображен модуль отчетов moodle
Рисунок 3 - Модуль отчета в moodle
После анализа существующих систем можно сделать вывод о том, какими свойствами должна обладать создаваемая система.
Рассмотрим подробнее способы достижения требований изложенных в прошлой главе. Первые три пункта кроссплатформенность, работу по сети и совместимость с moodle можно выполнить, реализовав систему в виде web-приложение. Система будет доступна с любого устройства, у которого есть доступ к сети. Для четвертого пункта необходимо выбрать СУБД. Среди некоммерческих СУБД, можно выделить две это PostgreSQL и Firebird. Для своей системы я выбирал Firebird т.к. это простая в эксплуатации и разработке СУБД.
Firebird - реляционная СУДБ, обладает многоверсионной архитектурой, обеспечивающей параллельную обработку оперативных и аналитических запросов (это возможно потому, что читающие пользователи не блокируют пишущих), компактность (дистрибутив 5Mb), высокую эффективность и мощную языковую поддержку для хранимых процедур и триггеров. [3][4] СУДБ легко работает с большими базами данных. Среди минусов можно отметить отсутствие кеша результатов запросов и отсутствие полнотекстовых индексов.
Основные характеристики Firebird
В качестве web-сервера будет использоваться Zope 2, это объектно-ориентированная платформа, сервер приложений, написанный на языке python, предназначенный для создания динамических web-приложений и интерактивных сайтов.
Он был выбран мной в качестве web-сервера так как протоколы WWW (HTTP, CGI и т.д.) часто неадекватны задачам и могут делать публикацию динамических данных неоправданно сложной. Их низкий уровень недостаточен для непосредственного создания многих классов web-приложений на их основе. Zope создает объектно-ориентированную оболочку вокруг этих низкоуровневых средств. С его помощью решение задачи происходит обычным путем - программист пишет набор иерархий классов, являющийся абстракцией предметной области, а Zope берет на себя труд по предоставлению доступа к экземплярам этих классов. [5]
Zope предоставляет программистам и администраторам простые, и в то же время мощные и гибкие механизмы управления безопасностью. Безопасность в Zope стоит на трех китах, трех базовых понятиях - пользователь, роль, и вид доступа, что удовлетворяет последнему пункту требований.
Вид, или тип доступа определяет программист при создании компонента. Каждому классу в компоненте определяется полномочие "Add" ("Добавить экземпляр класса в дерево объектов"), каждому методу класса можно определить свои собственные полномочия, которые определят, кому и какой вид доступа предоставлен к этому методу класса. Например, методу index_html (который вызывается при обращении к объекту, а не к конкретному методу) обычно дается вид доступа View. Но это дело программиста, как назвать свои полномочия, и какие методы какими полномочиями защитить. Обычно методы объекта объединяются в группы, предоставляющие один сервис. Например, класс Новостная Лента может иметь сервисы (группы методов) "показ новостей", "добавление новостей", "редактирование новостей", "удаление новостей", "добавление/редактирование/удаление рубрик". И каждый из сервисов можно защитить (дав ему отдельный вид доступа) - с точностью до одного метода. Для более тонкого управления, уже внутри метода, программист может запросить Security Manager - "имеет ли текущий пользователь права на создание DTML Методов в Папке Razdel?"
Роли создает администратор сайта через менеджерский web-интерфейс Zope. Понятие роли распространяется не на весь сайт, не на ZODB, а на часть дерева. Администратор создает роль в какой-то папке, и дальше благодаря механизму acquisition эта роль распространяется вниз по поддереву.
Zope, поставленная из дистрибутива, имеет 3 роли, определенные в корне ZODB - Anonymous, Owner и Manager. Manager - это такой всесильный администратор, аналог рута. Owner - владелец тех ресурсов, которые он создал. Анонимный пользователь - просто посетитель сайта; ему изначально доступны типы доступа: Access content, View, Use SQL Methods (это для того, чтобы позволить вызывать SQL Методы из DTML Методов) и Search ZCatalog. Администратор сайта в дальнейшем может создавать новые роли, как в корне, если у самого администратора есть права на редактирование корня, так и в любых поддеревьях, на которые у администратора есть права.
Большинство кода Zope реализована на языке python, за исключением небольшого числа модулей написанных на C для повышения производительности. Python является многоцелевым, объектно-ориентированным языком программирования. Python представляет собой полноценный язык программирования, используемый для создания приложений любого типа. В отличии от PHP который ориентирован на разработку web-приложений. Богатый набор дополнительных модулей может быть использован для создания веб-приложений на основе Python. Python является интерпретируемым языком и ориентирована на выполнение "сценариев" в первую очередь. Это не означает, что Python приложение не может быть большими и сложными. Используя Python можно создавать сложные приложения. Установочный пакет Python содержит богатый набор модулей, которые охватывают большую часть функционала, необходимого типичному разработчику. Дополнительные модули могут быть загружены и установлены из хранилища индекса PyPI. PyPI содержащего более 14 000 дополнительных сторонних модулей (по состоянию на май 2011 г.).
Python прост в освоении. Синтаксис и концепции Python очень легко узнать и понять. Средний разработчика, как правило, в состоянии изучить основы в течение дня или двух. Код python обычно читаемый и понятный (например, по сравнению с Perl).[10]
Для динамического построения страниц из шаблонов в Zope применяется язык TAL
TAL является системой шаблонов Zope Page Template (ZPT). TAL поддерживает пространства имен TAL, METAL и I18N.
TALES является эквивалентом TALES, Template Attribute Language Expression Syntax (синтаксис атрибутивного языка шаблонов). Он определяет, как обрабатываются значения атрибутов XML.
Так как PTALES подобен TALES, TAL шаблоны python и PHP могут одинаково использоваться и транспортироваться из одного языка в другой.
Чтобы быть совместимым с PHPTAL, TAL реализует XPath-подобный доступ к данным.[6]
Для подключения к Firebird используется продукт kinterbasDA. Продукты - компоненты, написанные программистом на Питоне - позволяют дополнять Zope новыми типами объектов. В нашем случае это драйвер для работы с СУБД. Он позволяет создавать параметризированные SQL методы. Вызывать методы можно непосредственно на странице, используя TAL шаблон, или в скрипте, написанном на языке Python.
Система состоит из формы авторизации и четырех модулей.
Каждый из модулей использует свой собственный коннект под отделенной для модуля ролью, с определенным набором прав и разрешений.
На следующем рисунке представлено схематическое строение модулей.
Рисунок 4 - Общая архитектура модулей.
Архитектура всех модулей однотипная, модуль состоит из одного или нескольких форм-шаблонов, передающих данные скриптам, написанным на языке python. Скрипты обрабатывают данные, после чего обращаются в базу, вызывая хранимые процедуры, в которых содержится логика модуля. В зависимости от результатов возвращаемых из базы в скрипте принимается решение о переходе на ту или иную форму. Данные для формы так же подгружаются из базы.
В высококачественном программировании должна быть очевидна связь между концептуальной целостностью архитектуры и её низкоуровневой реализации. Реализация должна соответствовать высокоуровневой архитектуре и обладать внутренней согласованностью. В этом заключается смысл принципов конструирования, определяющих конвенции именования переменных, классов, методов, а так еж форматирования кола и оформления переменных.
При разработке сложной программы архитектурные принципы вносят в программу структурный баланс, а принципы конструирования низкоуровневую гармонию, при наличии каторой каждый класс определяется как неотъемлемая часть общего плана. Любая крупная программа требует применения контролирующей структуры, унифицирующей аспекты языка программирования. Красота крупной структуры частично заключается в том, как в её отдельных компонентах выражены особенности архитектуры. Без унификации программа будет смесью небрежных вариаций стиля, заставляющих прилагать дополнительные усилия только для того, чтобы различия в стиле кодирования, которые вполне можно было избежать. Одно из условий успешного программирования устранение ненужных вариаций, позволяющее сосредоточиться на днйствительно необходимых вариациях. [11]
База состоит из 10 основных таблиц.
Таблица пользователей L_USERS в которой храниться информация о пользователях. Таблица состоит из следующих полей, целочисленного идентификатор записи (первичный ключ), ФИО сотрудника, статус записи, внешний ключ связывающий таблицу с таблицей групп пользователей L_USER_GROUP, логин, зашифрованный пароль, даты последнего изменения записи, имени последнего пользователя изменявшего запись.
Таблица групп пользователей L_USER_GROUP состоит из целочисленного идентификатора записи (первичный ключ), наименования группы, уникального символьного кода группы, полей с разрешениями на модули для каждой группы, даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
Таблица сессий L_SESSION, хранит информацию о сессиях пользователей (времени входа и выхода) в системе. Состоит из целочисленного идентификатора (первичного ключа), идентификатора пользователя (внешний ключ на таблицу L_USERS), времени входа и выхода из системы.
Таблица тем (список тем из различных областей знаний) L_THEME. Состоит из целочисленного идентификатора записи (первичного ключа), наименования темы, текстового уникального кода темы, поля с описанием темы, статуса записи в таблице, идентификатора родительской записи (внешний ключ, связывание таблицы собой же), даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
Таблица закрепления пользователя за темой L_USER_THEMS. Состоит из целочисленного идентификатора записи (первичный ключ), идентификатора темы (внешний ключ), идентификатора пользователя (внешний ключ) даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
Таблица содержащая реестр тестов L_TESTS. Состоит из целочисленного идентификатора записи (первичный ключ), идентификатора темы (внешний ключ на таблицу L_THEME), наименования теста, описания теста, статуса записи, идентификатора пользователя создавшего сайт (внешний ключ на таблицу L_USER), поля с временем, за которое нужно выполнить тест, даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
Таблица L_QUESTION список вопросов в тестах. Состоит из целочисленного идентификатора записи (первичного ключа), идентификатора теста (внешний ключ на таблицу L_TESTS), текста вопроса, идентификатора типа теста (внешний ключ на таблицу L_QUEST_TYPE), статуса записи, порядкового номера вопроса в тесте, даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
Таблица L_QUEST_TYPE список типов вопросов, и их параметров.
Состоит из целочисленного идентификатора записи ( первичного ключа), уникального символьного кода, наименования типа, флага текстового ответа, флага выбора одного, максимальное кол-во вариантов ответа, даты последнего изменения записи и имени последнего пользователя редактировавшего запись. В зависимости от типа вопроса, в интерфейсе задаются правила отображения вопроса и формата ответа на него.
Таблица вариантов ответов L_ANSWER по вопросу. Состоит из целочисленного идентификатора записи (первичный ключ), текста ответа, отображаемого в интерфесе, идентификатора вопроса (внешний ключ на таблицу L_QUESTION), статус записи в таблице, флаг корректности ответа, для вопросов с выбором правильного ответа, количества балов, начисляемое за ответ, даты последнего изменения записи и имени последнего пользователя редактировавшего запись
Таблицы D_RESULT и S_RESULT таблицы результатов прохождения тестов, относительно набора атрибуов имеют одинаковую структуру. Состоят из целочисленного идентификатора записи (первичного ключа), идентификатора теста, идентификатора вопроса, идентификатора выбранного ответа, идентификтаора сессии, кол-ва заработанных балов за ответ, статуса записи в таблице, даты последнего изменения записи и имени последнего пользователя редактировавшего запись.
На рисунке 5 изображена схематическая структура базы.
Рисунок 5 - Схематическая связь таблиц в базе.
Одним из методов создания страниц в Zope является панель администратора Zope (Рисунок 6). Расположенная по адресу http://zopehost:zopeport/manage, где zopehost ip-адрес сервера, на котором установлен Zope сервер, а zopeport порт который прослушивает сервер, по умолчанию это 8080. Так же вести разрботку можно через FTP или WebDAV.
Рисунок 6 Панель администратора в Zope2.
Создание html страниц в Zope
Для создания html страницы в выпадающем списке выберем элемент Page Template, представляющий из себя html шаблон. Шаблоны страниц должны удовлетворять трем основным правилам:
Шаблон страницы подобен модели страниц, которые он генерирует. В частности, он является правильной HTML страницей [8].
В качестве обработчика данных с формы используются скрипты написанные на языке python.
Рассмотрим создание простого шаблона (рисунки 7, 8) с использованием языка TAL.
Рисунок 7 - Форма авторизации при входе в систему
без сообщения.
Рисунок 8 - Форма авторизации при входе в систему
с сообщением.
Форма является шаблоном, написанным на обычном html, а появляющееся сообщение на красном фоне является результатом использования TAL шаблонизатора, рассмотрим эту часть кода.
<span tal:condition="options/err">
<p align="center" style="background-color:#FF0000">
<font size=4 color=#FFFFFF tal:content="python: options.get('err','')">
</font>
</p>
</span>
Здесь использованы две конструкции tal, это condition и content.
Condition условие, при наличии значения err передаваемого на форму тег в котором установлено условие и все вложенные в него отображаются, иначе не отображаются.
Content описывает содержимое того тега, в котором оно находиться. В нашем случае это текст сообщения содержащийся в переменной err. Конструкции языка tal могут использовать как стандартные конструкции, так и встроенные конструкции языка python как в примере с конструкцией content.
Tal шаблоны так же позволяют строить динамические списки.
Например построение списка типов вопросов на форме создания тестов (рисунок 9).
Рисунок 9 Список типов вопросов.
Код описывающий построение списка.
<span tal:repeat="item python: container.SQL_QUEST_TYPE()">
<input type="radio" name="type" tal:attributes="id item/ID_QUESTTYPE"> <span tal:content="item/NAME" /> <br>
</span>
Tal:repeat конструкция определяющая повторяющийся тег, со всем своим содержимым. Повторяться он будет столько раз, сколько строк вернет Z SQL метод SQL_QUEST_TYPE. Z SQL методы объекты Zope для создания параметризированных запросов к базе данных.
Пример SQL метода:
SELECT OUT_ID_QUESTION, OUT_STATUS, OUT_NUM,
OUT_QUESTION_DESCRIPTION, OUT_ID_TEST
FROM REP_GET_QUESTION_LIST(<DTML-SQLVAR ID_TEST TYPE="INT"OPTIONAL >)
Запрос вызывающий хранимую процедуру и передающий в неё идентификатор теста для получения списка вопросов по этому тесту.
Рассмотрим обработку данных на примере формы регистрации
Объявим методы request и RESPONSE.
request = container.REQUEST
RESPONSE = request.RESPONSE
Запросим из полученного набора присланных данных значения полей с логином и паролем
login= request.get('login','')
passw = request.get('passw','')
Удостоверимся, что значения не являются пустыми
if (login==''):
Если значение пустое, то выведем снова форму логина, дополнительно передав на нее сообщение о пустом логине или пароде
return container.Login(err='Вы не ввели логин')
elif (passw==''):
return container.Login(err='Вы не ввели пароль')
else:
Если же поля заполнены, то вызываем через параметризованный ZSQL метод процедуру для проверки правильности введенных логина и пароля. Значения возращенные процедурой запишем в переменную log.
log = container.P_LOGIN(login=login, passw=passw)[0]
Если пароль и логин подтвердились, то переходим на форму со списком модулей и передаем на неё идентификатор сессии под которым будет работать пользователь.
if (log.OUT_SUCCESS=='1'):
return RESPONSE.redirect('Iface?id_session=%s' % (log.OUT_ID_SESSION))
else:
Иначе вернемся на форму регистрации с сообщением об ошибке.
return container.Login(err = log.OUT_MESSAGE).
Для написания процедур используется PSQL расширение языка SQL для СУБД Firebird. Основными элементами являются циклы и логические операторы.
Каждая процедура состоит из следующих обязательных выражений
Объявление действия совершаемого над процедурой, в скобках перечисляются входные параметры процедуры.
CREATE OR ALTER PROCEDURE PROCEDURE_NAME ()
В конструкции в скобках RETURNS () перечисляются выходные параметры которые будут выведены процедурой после вызова команды SUSPEND. Команды BEGIN и END обозначают конец и начало блока с текстом процедуры. Ниже приведен пример простейшего цикла, который выбирает все варианты ответов по вопросу, присваивая каждому варианту ответа свой номер начиная с одного.
OUT_NUMBER = 0;
Объявляем массив, который будем обрабатывать.
FOR
SELECT la.ID_ANSWER, la.IS_CORRECT, la.TEXT, la.SCORE
FROM L_ANSWER la
WHERE la.ID_QUERY = :IN_QUESTION_NUMBER
Переменные, которым будут присваиваться значения из массива.
INTO :OUt_ID_ANSWER, :OUT_IS_CORRECT, :OUT_TEXT, :OUT_SCORE
DO BEGIN
Тело цикла с инкрементом счетчика и выводом информации.
OUT_NUMBER = OUT_NUMBER +1;
SUSPEND;
END
Модуль создания тестов предназначен для создания новых и редактирования существующих тестов. Модуль состоит из трёх форм, формы выбора теста для редактирования, непосредственно формы редактирования и формы создания нового теста. Права на модуль имеют только пользователи, входящие в группу преподавателей. Остальные пользователи не имеют возможности зайти в этот модуль. На рисунке 10 изображена форма редактирования тестов, модуля создания тестов.
Рисунок 10 Форма редактирования теста.
Модуль прохождения тестов предназначен для прохождения тестов. Модуль состоит из двух форм, формы выбора теста для прохождения и формы и непосредственно формы прохождения тестов, подгружающего данные в различном формате, в зависимости от типа вопроса. Права на модуль есть у всех пользователей, а возможностью проходить все тесты без назначения, обладают только пользователи из группы администратор и из группы преподаватели. На рисунке 11 изображен пример интерфейса.
Рисунок 11 Форма прохождения тестов.
Модуль назначения тестов предназначен для назначения пользователям тестов на прохождение. Состоит из формы со списком пользователей и тестов и формы для просмотра привязанных к пользователю тестов.. Модуль доступен для пользователей из группы администратор и из группы преподаватели.
Модуль предназначен для просмотра статистики по пройденным тестам. Модуль доступен всем пользователям, но внутри модуля существуют ограничения на запуск тех или иных отчетов. Модуль состоит из формы со списком отчетов, и множества форм самих отчетов.
Основные результаты дипломной (курсовой) работы состоят в следующем:
1) Проведен анализ существующих систем для тестирования и сбора результатов. Выявлены достоинства и недостатки каждой из рассмотренных систем.
2) На основе анализа существующих систем сформулированы концепции разрабатываемой системы, на основе была спроектирована архитектура разрабатываемой системы.
3) Была спроектирована структура базы данных, с учетом специфики использования системы, для хранения больших объемов данных.
4) Спроектированы интерфейсы для системы мониторинга уровня знаний.
5) Была разработана система мониторинга уровня знаний учащихся.
Практическая значимость проведенной разработки состоит в возможности комплексного оценивания уровня знаний учащихся. Система может применяться в любых учебных заведениях, для сбора статистики по результатам тестов и проведения анализ собранных данных.
1. Основные возможности UniTest System. URL: http://sight2k.com/rus/unitest/qtour/ [2 сентября 2012]
2. MyTest - Компьютерное тестирование знаний UPL: http://mytest.klyaksa.net/ [26 сентября 2012]
3. Firebird: About Firebird 25 января 2013 URL: http://www.firebirdsql.org/en/about-firebird/ [4 февраля 2013]
4. iBase.ru | Firebird 18 марта 2012 URL: http://www.ibase.ru/firebird.htm [15 марта 2013]
5. Zope - The Object Publishing Environment URL: http://lib.misto.kiev.ua/WEBMASTER/zope.txt [20 октября 2012]
6. PHPTAL URL: http://phptal.org/manual/ru/#introduction [12 декабря 2012]
7. Moodle.org: open-source community-based tools for learning URL: http://moodle.org [30 сентября 2012]
8. Plone.org.ru: wikipage - Сайт поддержки систем управления сайтами Plone, Zope, языка python 19 августа 2006. URL: http://plone.org.ru/docs/howto/ZPT [16 ноября 2012]
9. Узнайте Firebird 23 сентября 2011 URL: http://www.firebirdnews.org/docs/fb2min_ru.html [29 октября 2012]
10 Zope uses Python The Zope 2 Application Server URL: http://zope2.zope.org/about-zope-2/six-reasons-for-using-zope/zope-uses-python [20 декабря 2012]
11 Макконелл С. Совершенный код. Мастер-класс / Пер. с англ. М. : Русская редакция, 2012 896 стр. : ил.
12 Марк Лутц Изучаем Python. / Пер. с англ. М. : Символ-Плюс 2011 1280 с.
13. Хелен Борри. Firebird: руководство разработчика баз данных / Пер. с англ. СПб «БХВ-Петербург» 2007 1104 с.
/******************************************************************************/
/*** Generated by IBExpert 2012.9.2.1 18.06.2013 23:24:13 ***/
/******************************************************************************/
SET SQL DIALECT 3;
SET NAMES WIN1251;
CREATE DATABASE '127.0.0.1:C:\Documents and Settings\Admin\Рабочий стол\SMUZ2.FDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 16384
DEFAULT CHARACTER SET WIN1251;
/******************************************************************************/
/*** Domains ***/
/******************************************************************************/
CREATE DOMAIN D1024VARCHAR AS
VARCHAR(1024);
CREATE DOMAIN D10CHAR AS
CHAR(10);
CREATE DOMAIN D128VARCHAR AS
VARCHAR(128);
CREATE DOMAIN D512VARCHAR AS
VARCHAR(512);
CREATE DOMAIN D60CHAR AS
CHAR(60);
CREATE DOMAIN D60VARCHAR AS
VARCHAR(60);
CREATE DOMAIN DATES AS
DATE;
CREATE DOMAIN DOUBLE_PREC AS
DOUBLE PRECISION;
CREATE DOMAIN INTT AS
INTEGER;
CREATE DOMAIN PRK AS
INTEGER
NOT NULL;
CREATE DOMAIN TIMEST AS
TIMESTAMP;
/******************************************************************************/
/*** Generators ***/
/******************************************************************************/
CREATE GENERATOR G_ID_ANSWER;
SET GENERATOR G_ID_ANSWER TO 21;
CREATE GENERATOR G_ID_GROUP;
SET GENERATOR G_ID_GROUP TO 0;
CREATE GENERATOR G_ID_QUERY;
SET GENERATOR G_ID_QUERY TO 3;
CREATE GENERATOR G_ID_QUERY_TYPE;
SET GENERATOR G_ID_QUERY_TYPE TO 10;
CREATE GENERATOR G_ID_RES_ANSWER;
SET GENERATOR G_ID_RES_ANSWER TO 0;
CREATE GENERATOR G_ID_RES_TEST;
SET GENERATOR G_ID_RES_TEST TO 0;
CREATE GENERATOR G_ID_SESSION;
SET GENERATOR G_ID_SESSION TO 0;
CREATE GENERATOR G_ID_TEST;
SET GENERATOR G_ID_TEST TO 1;
CREATE GENERATOR G_ID_THEM;
SET GENERATOR G_ID_THEM TO 0;
CREATE GENERATOR G_ID_USER;
SET GENERATOR G_ID_USER TO 0;
CREATE GENERATOR G_ID_USER_GROUP;
SET GENERATOR G_ID_USER_GROUP TO 0;
SET TERM ^ ;
/******************************************************************************/
/*** Stored Procedures ***/
/******************************************************************************/
CREATE PROCEDURE ADD_VARIANT (
IN_ID_QUESTION INTEGER,
IN_TEXT VARCHAR(128),
IN_IS_CORRECT INTEGER,
IN_SCORE DOUBLE PRECISION)
RETURNS (
I INTEGER)
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE GENERATE_TRIGGER
RETURNS (
OUT_TRIG_TEXT VARCHAR(10000))
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE REP_GET_QUERY_TEXT (
IN_ID_QUERY INTEGER)
RETURNS (
TEXT VARCHAR(512))
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE REP_GET_QUESTION_LIST (
IN_ID_TEST INTEGER)
RETURNS (
OUT_ID_TEST INTEGER,
OUT_ID_QUESTION INTEGER,
OUT_NUM INTEGER,
OUT_QUESTION_DESCRIPTION VARCHAR(128))
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE REP_GET_VARIANT (
IN_QUESTION_NUMBER INTEGER)
RETURNS (
OUT_ID_ANSWER INTEGER,
OUT_IS_CORRECT INTEGER,
OUT_TEXT VARCHAR(128),
OUT_SCORE DOUBLE PRECISION,
OUT_NUMBER INTEGER,
OUT_AUERY_TEXT VARCHAR(512))
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE W_ADD_QUERY (
IN_ID_TEST INTEGER)
RETURNS (
OUT_ID_QUERY INTEGER)
AS
BEGIN
SUSPEND;
END^
CREATE PROCEDURE W_SAVE_QUERY (
IN_ID_QUERY INTEGER,
IN_QUERY_TEXT VARCHAR(512),
IN_TEXT_1 VARCHAR(128),
IN_TEXT_2 VARCHAR(128),
IN_TEXT_3 VARCHAR(128),
IN_TEXT_4 VARCHAR(128),
IN_TEXT_5 VARCHAR(128),
IN_CORRECT_1 VARCHAR(5),
IN_CORRECT_2 VARCHAR(5),
IN_CORRECT_3 VARCHAR(5),
IN_CORRECT_4 VARCHAR(5),
IN_CORRECT_5 VARCHAR(5),
IN_SCORE_1 DOUBLE PRECISION,
IN_SCORE_2 DOUBLE PRECISION,
IN_SCORE_3 DOUBLE PRECISION,
IN_SCORE_4 DOUBLE PRECISION,
IN_SCORE_5 DOUBLE PRECISION)
RETURNS (
OUT_SUCCESS INTEGER,
OUT_MESSAGE VARCHAR(128))
AS
BEGIN
SUSPEND;
END^
SET TERM ; ^
/******************************************************************************/
/*** Tables ***/
/******************************************************************************/
CREATE TABLE D_RES_ANSWER (
ID_RES_ANSWER PRK,
ID_RES_TEST INTT,
ID_TEST INTT,
ID_ANSWER INTT,
ID_SESSION INTT,
BEGINTIME TIMEST,
ENDTIME TIMEST,
IS_CORRECT INTT,
SCORE DOUBLE_PREC,
PROCENT DOUBLE_PREC,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE D_RES_TEST (
ID_RES_TEST PRK,
ID_TEST INTT,
ID_SESSION INTT,
BEGINTIME TIMEST,
ENDTIME TIMEST,
RESULT DOUBLE_PREC,
PROCENT DOUBLE_PREC,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE HEL (
TAB VARCHAR(100),
ATR VARCHAR(100)
);
CREATE TABLE L_ANSWER (
ID_ANSWER PRK,
ID_QUERY INTT,
NUM INTT,
TEXT D512VARCHAR,
IS_CORRECT INTT,
SCORE DOUBLE_PREC,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_GROUP (
ID_GROUP PRK,
NAME D128VARCHAR,
CODE D10CHAR,
ALLOW_EDIT INTT,
ALLOW_ASSEMBLE INTT,
ALLOW_STAT INTT,
ALLOW_TEST INTT,
PARAMS D1024VARCHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_QUERY (
ID_QUERY PRK,
ID_QUERY_TYPE INTT,
ID_TEST INTT,
ID_THEM INTT,
NUM INTT,
TEXT D512VARCHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_SESSION (
ID_SESSION PRK,
ID_USER INTT,
CONNECTTIME TIMEST,
DISCONNECTTIME TIMEST,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_TEST (
ID_TEST PRK,
ID_THEM INTT,
NAME D128VARCHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_THEM (
ID_THEM PRK,
NAME D128VARCHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_USER (
ID_USER PRK,
NAME D128VARCHAR,
FIRSTNAME D128VARCHAR,
LASTNAME D128VARCHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE L_USER_GROUP (
ID_USER_GROUP PRK,
ID_USER INTT,
ID_GROUP INTT,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
CREATE TABLE S_QUERY_TYPE (
ID_QUERY_TYPE PRK,
NAME D128VARCHAR,
CODE D10CHAR,
STATUS INTT,
LASTDATE TIMEST,
USERNAME D10CHAR
);
/******************************************************************************/
/*** Primary Keys ***/
/******************************************************************************/
ALTER TABLE D_RES_ANSWER ADD CONSTRAINT PK_D_RES_ANSWER PRIMARY KEY (ID_RES_ANSWER);
ALTER TABLE D_RES_TEST ADD CONSTRAINT PK_D_RES_TEST PRIMARY KEY (ID_RES_TEST);
ALTER TABLE L_ANSWER ADD CONSTRAINT PK_L_ANSWER PRIMARY KEY (ID_ANSWER);
ALTER TABLE L_GROUP ADD CONSTRAINT PK_L_GROUP PRIMARY KEY (ID_GROUP);
ALTER TABLE L_QUERY ADD CONSTRAINT PK_L_QUERY PRIMARY KEY (ID_QUERY);
ALTER TABLE L_SESSION ADD CONSTRAINT PK_L_SESSION PRIMARY KEY (ID_SESSION);
ALTER TABLE L_TEST ADD CONSTRAINT PK_L_TEST PRIMARY KEY (ID_TEST);
ALTER TABLE L_THEM ADD CONSTRAINT PK_L_THEM PRIMARY KEY (ID_THEM);
ALTER TABLE L_USER ADD CONSTRAINT PK_L_USER PRIMARY KEY (ID_USER);
ALTER TABLE L_USER_GROUP ADD CONSTRAINT PK_L_USER_GROUP PRIMARY KEY (ID_USER_GROUP);
ALTER TABLE S_QUERY_TYPE ADD CONSTRAINT PK_S_QUERY_TYPE PRIMARY KEY (ID_QUERY_TYPE);
/******************************************************************************/
/*** Triggers ***/
/******************************************************************************/
SET TERM ^ ;
/******************************************************************************/
/*** Triggers for tables ***/
/******************************************************************************/
/* Trigger: TR_D_RES_ANSWER_BI */
CREATE TRIGGER TR_D_RES_ANSWER_BI FOR D_RES_ANSWER
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.id_res_answer IS NULL) THEN
BEGIN
SELECT GEN_ID(G_id_res_answer,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.id_res_answer = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_D_RES_ANSWER_BU */
CREATE TRIGGER TR_D_RES_ANSWER_BU FOR D_RES_ANSWER
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_D_RES_TEST_BI */
CREATE TRIGGER TR_D_RES_TEST_BI FOR D_RES_TEST
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_RES_TEST IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_RES_TEST,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_RES_TEST = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_D_RES_TEST_BU */
CREATE TRIGGER TR_D_RES_TEST_BU FOR D_RES_TEST
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_ANSWER_BI */
CREATE TRIGGER TR_L_ANSWER_BI FOR L_ANSWER
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_ANSWER IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_ANSWER,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_ANSWER = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_ANSWER_BU */
CREATE TRIGGER TR_L_ANSWER_BU FOR L_ANSWER
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_GROUP_BI */
CREATE TRIGGER TR_L_GROUP_BI FOR L_GROUP
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_GROUP IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_GROUP,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_GROUP = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_GROUP_BU */
CREATE TRIGGER TR_L_GROUP_BU FOR L_GROUP
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_QUERY_BI */
CREATE TRIGGER TR_L_QUERY_BI FOR L_QUERY
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_QUERY IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_QUERY,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_QUERY = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_QUERY_BU */
CREATE TRIGGER TR_L_QUERY_BU FOR L_QUERY
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_SESSION_BI */
CREATE TRIGGER TR_L_SESSION_BI FOR L_SESSION
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_SESSION IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_SESSION,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_SESSION = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_SESSION_BU */
CREATE TRIGGER TR_L_SESSION_BU FOR L_SESSION
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_TEST_BI */
CREATE TRIGGER TR_L_TEST_BI FOR L_TEST
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_TEST IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_TEST,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_TEST = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_TEST_BU */
CREATE TRIGGER TR_L_TEST_BU FOR L_TEST
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_THEM_BI */
CREATE TRIGGER TR_L_THEM_BI FOR L_THEM
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_THEM IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_THEM,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_THEM = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_THEM_BU */
CREATE TRIGGER TR_L_THEM_BU FOR L_THEM
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_USER_BI */
CREATE TRIGGER TR_L_USER_BI FOR L_USER
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_USER IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_USER,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_USER = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_USER_BU */
CREATE TRIGGER TR_L_USER_BU FOR L_USER
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_L_USER_GROUP_BI */
CREATE TRIGGER TR_L_USER_GROUP_BI FOR L_USER_GROUP
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_USER_GROUP IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_USER_GROUP,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_USER_GROUP = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_L_USER_GROUP_BU */
CREATE TRIGGER TR_L_USER_GROUP_BU FOR L_USER_GROUP
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
/* Trigger: TR_S_QUERY_TYPE_BI */
CREATE TRIGGER TR_S_QUERY_TYPE_BI FOR S_QUERY_TYPE
ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.ID_QUERY_TYPE IS NULL) THEN
BEGIN
SELECT GEN_ID(G_ID_QUERY_TYPE,1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.ID_QUERY_TYPE = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END
^
/* Trigger: TR_S_QUERY_TYPE_BU */
CREATE TRIGGER TR_S_QUERY_TYPE_BU FOR S_QUERY_TYPE
ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
^
SET TERM ; ^
/******************************************************************************/
/*** Stored Procedures ***/
/******************************************************************************/
SET TERM ^ ;
ALTER PROCEDURE ADD_VARIANT (
IN_ID_QUESTION INTEGER,
IN_TEXT VARCHAR(128),
IN_IS_CORRECT INTEGER,
IN_SCORE DOUBLE PRECISION)
RETURNS (
I INTEGER)
AS
BEGIN
IF (in_ID_QUESTION IS NULL) THEN
EXIT;
IF (IN_TEXT IS NULL ) THEN IN_TEXT = '';
IF (IN_IS_CORRECT IS NULL) THEN IN_IS_CORRECT = 0;
IF (IN_SCORE IS NULL ) THEN IN_SCORE = 0.0;
SELECT COUNT(*) FROM L_ANSWER WHERE ID_QUERY = :IN_ID_QUESTION
INTO i;
IF (i<5 ) THEN
INSERT INTO L_ANSWER (ID_QUERY, TEXT,IS_CORRECT, SCORE )
VALUES (:IN_ID_QUESTION, :IN_TEXT, :IN_IS_CORRECT, :IN_SCORE);
SUSPEND;
END^
ALTER PROCEDURE GENERATE_TRIGGER
RETURNS (
OUT_TRIG_TEXT VARCHAR(10000))
AS
DECLARE VARIABLE V_TAB VARCHAR(50);
DECLARE VARIABLE V_ATR VARCHAR(50);
BEGIN
FOR
SELECT TRIM(TAB), TRIM(ATR)
FROM HEL
INTO :V_TAB, :V_ATR
DO BEGIN
OUT_TRIG_TEXT = 'CREATE OR ALTER TRIGGER TR_'|| V_TAB ||'_BI FOR ' || V_TAB ||
' ACTIVE BEFORE INSERT POSITION 0
AS
DECLARE VARIABLE v_ID integer;
BEGIN
IF (NEW.'|| V_ATR || ' IS NULL) THEN
BEGIN
SELECT GEN_ID(G_'|| V_ATR ||',1)
FROM RDB$DATABASE
INTO :v_ID;
NEW.'|| V_ATR || ' = :V_ID;
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END
END;';
EXECUTE STATEMENT :OUT_TRIG_TEXT;
SUSPEND;
OUT_TRIG_TEXT = 'CREATE OR ALTER TRIGGER TR_'|| V_TAB ||'_BU FOR ' || V_TAB ||
' ACTIVE BEFORE UPDATE POSITION 0
AS
BEGIN
new.lastdate = CURRENT_TIMESTAMP;
new.username = user;
END;';
EXECUTE STATEMENT :OUT_TRIG_TEXT;
SUSPEND;
END
END^
ALTER PROCEDURE REP_GET_QUERY_TEXT (
IN_ID_QUERY INTEGER)
RETURNS (
TEXT VARCHAR(512))
AS
BEGIN
SELECT TEXT
FROM L_QUERY
WHERE ID_QUERY = :in_ID_QUERY
into :text;
IF (:text is null) THEN
text='';
SUSPEND;
END^
ALTER PROCEDURE REP_GET_QUESTION_LIST (
IN_ID_TEST INTEGER)
RETURNS (
OUT_ID_TEST INTEGER,
OUT_ID_QUESTION INTEGER,
OUT_NUM INTEGER,
OUT_QUESTION_DESCRIPTION VARCHAR(128))
AS
BEGIN
FOR
/*получаем по ид-теста список вопросов для прорисовки на странице*/
SELECT LQ.ID_QUERY, LQ.ID_TEST, LQ.NUM, 'Вопрос № '|| INTTOSTR(LQ.NUM, '%d')
FROM L_QUERY LQ
WHERE LQ.ID_TEST = :IN_ID_TEST
INTO :OUT_ID_QUESTION, :OUT_ID_TEST, :OUT_NUM, :OUT_QUESTION_DESCRIPTION
DO SUSPEND;
END^
ALTER PROCEDURE REP_GET_VARIANT (
IN_QUESTION_NUMBER INTEGER)
RETURNS (
OUT_ID_ANSWER INTEGER,
OUT_IS_CORRECT INTEGER,
OUT_TEXT VARCHAR(128),
OUT_SCORE DOUBLE PRECISION,
OUT_NUMBER INTEGER,
OUT_AUERY_TEXT VARCHAR(512))
AS
BEGIN
/*Получаем список вариантов ответа по вопросу*/
SELECT TEXT
FROM L_QUERY
WHERE ID_QUERY = :IN_QUESTION_NUMBER
INTO :OUT_AUERY_TEXT;
out_number = 0;
FOR
SELECT la.ID_ANSWER, la.IS_CORRECT, la.TEXT, la.SCORE
FROM L_ANSWER la
WHERE la.ID_QUERY = :IN_QUESTION_NUMBER
ORDER BY ID_ANSWER
INTO :OUt_ID_ANSWER, :OUT_IS_CORRECT, :OUT_TEXT, :OUT_SCORE
DO BEGIN
OUT_NUMBER = OUT_NUMBER +1;
SUSPEND;
END
END^
ALTER PROCEDURE W_ADD_QUERY (
IN_ID_TEST INTEGER)
RETURNS (
OUT_ID_QUERY INTEGER)
AS
DECLARE VARIABLE V_NUM INTEGER;
BEGIN
/*ДОБАВЛЯЕМ ЗАПИСЬ В СПИСОК ВОПРОСОВ ТЕСТА*/
SELECT MAX(Q.NUM)+1
FROM L_QUERY Q
WHERE Q.ID_TEST = :IN_ID_TEST
INTO :V_NUM;
SELECT GEN_ID(G_ID_QUERY_TYPE,1)
FROM RDB$DATABASE
INTO :OUT_ID_QUERY;
INSERT INTO L_QUERY (ID_QUERY, ID_TEST, NUM)
VALUES (:OUT_ID_QUERY, :IN_ID_TEST, :V_NUM);
SUSPEND;
END^
ALTER PROCEDURE W_SAVE_QUERY (
IN_ID_QUERY INTEGER,
IN_QUERY_TEXT VARCHAR(512),
IN_TEXT_1 VARCHAR(128),
IN_TEXT_2 VARCHAR(128),
IN_TEXT_3 VARCHAR(128),
IN_TEXT_4 VARCHAR(128),
IN_TEXT_5 VARCHAR(128),
IN_CORRECT_1 VARCHAR(5),
IN_CORRECT_2 VARCHAR(5),
IN_CORRECT_3 VARCHAR(5),
IN_CORRECT_4 VARCHAR(5),
IN_CORRECT_5 VARCHAR(5),
IN_SCORE_1 DOUBLE PRECISION,
IN_SCORE_2 DOUBLE PRECISION,
IN_SCORE_3 DOUBLE PRECISION,
IN_SCORE_4 DOUBLE PRECISION,
IN_SCORE_5 DOUBLE PRECISION)
RETURNS (
OUT_SUCCESS INTEGER,
OUT_MESSAGE VARCHAR(128))
AS
DECLARE VARIABLE V_ID_ANSWER INTEGER;
DECLARE VARIABLE V_CORRECT INTEGER;
DECLARE VARIABLE v_num INTEGER;
BEGIN
/*Процедура сохраняет данные с формы*/
OUT_MESSAGE = 'Вопрос сохранен.';
/*запишем параметры вопроса*/
FOR
SELECT ID_ANSWER, NUM
FROM L_ANSWER
WHERE ID_QUERY = :IN_ID_QUERY
ORDER BY NUM
INTO :V_ID_ANSWER, :V_NUM
DO BEGIN
/*---------------------------------------------------------------------------*/
IF (V_NUM = 1 ) THEN
BEGIN
IF (IN_TEXT_1 = '') THEN
DELETE FROM L_ANSWER
WHERE ID_ANSWER =:V_ID_ANSWER;
ELSE
BEGIN
IF (IN_CORRECT_1= 'on')
THEN V_CORRECT = 1;
ELSE V_CORRECT = 0;
UPDATE L_ANSWER
SET TEXT = :IN_TEXT_1,
IS_CORRECT = :V_CORRECT,
SCORE = :IN_SCORE_1
WHERE ID_ANSWER =:V_ID_ANSWER;
END
END
/*---------------------------------------------------------------------------*/
IF (V_NUM = 2 ) THEN
BEGIN
IF (IN_TEXT_2 = '') THEN
DELETE FROM L_ANSWER
WHERE ID_ANSWER =:V_ID_ANSWER;
ELSE
BEGIN
IF (IN_CORRECT_2= 'on')
THEN V_CORRECT = 1;
ELSE V_CORRECT = 0;
UPDATE L_ANSWER
SET TEXT = :IN_TEXT_2,
IS_CORRECT = :V_CORRECT,
SCORE = :IN_SCORE_2
WHERE ID_ANSWER =:V_ID_ANSWER;
END
END
/*---------------------------------------------------------------------------*/
IF (V_NUM = 3 ) THEN
BEGIN
IF (IN_TEXT_3 = '') THEN
DELETE FROM L_ANSWER
WHERE ID_ANSWER =:V_ID_ANSWER;
ELSE
BEGIN
IF (IN_CORRECT_3= 'on')
THEN V_CORRECT = 1;
ELSE V_CORRECT = 0;
UPDATE L_ANSWER
SET TEXT = :IN_TEXT_3,
IS_CORRECT = :V_CORRECT,
SCORE = :IN_SCORE_3
WHERE ID_ANSWER =:V_ID_ANSWER;
END
END
/*---------------------------------------------------------------------------*/
IF (V_NUM = 4 ) THEN
BEGIN
IF (IN_TEXT_4 = '') THEN
DELETE FROM L_ANSWER
WHERE ID_ANSWER =:V_ID_ANSWER;
ELSE
BEGIN
IF (IN_CORRECT_4= 'on')
THEN V_CORRECT = 1;
ELSE V_CORRECT = 0;
UPDATE L_ANSWER
SET TEXT = :IN_TEXT_4,
IS_CORRECT = :V_CORRECT,
SCORE = :IN_SCORE_4
WHERE ID_ANSWER =:V_ID_ANSWER;
END
END
/*---------------------------------------------------------------------------*/
IF (V_NUM = 5 ) THEN
BEGIN
IF (IN_TEXT_5 = '') THEN
DELETE FROM L_ANSWER
WHERE ID_ANSWER =:V_ID_ANSWER;
ELSE
BEGIN
IF (IN_CORRECT_5= 'on')
THEN V_CORRECT = 1;
ELSE V_CORRECT = 0;
UPDATE L_ANSWER
SET TEXT = :IN_TEXT_5,
IS_CORRECT = :V_CORRECT,
SCORE = :IN_SCORE_5
WHERE ID_ANSWER =:V_ID_ANSWER;
END
END
/*---------------------------------------------------------------------------*/
END
/*сохраним текст вопроса*/
IF (C(IN_QUERY_TEXT)='') THEN
BEGIN
DELETE FROM L_QUERY
WHERE ID_QUERY = :IN_ID_QUERY;
DELETE FROM L_ANSWER
WHERE ID_QUERY = :IN_ID_QUERY;
OUT_MESSAGE = 'Вопрос удален.';
END
ELSE
UPDATE L_QUERY
SET TEXT = :IN_QUERY_TEXT
WHERE ID_QUERY = :IN_ID_QUERY;
/*исправим нумерацию если её сбили*/
V_NUM = 1;
FOR
SELECT ID_ANSWER
FROM L_ANSWER
WHERE ID_QUERY = :IN_ID_QUERY
ORDER BY NUM
INTO :V_ID_ANSWER
DO BEGIN
UPDATE L_ANSWER
SET NUM = :V_NUM
WHERE ID_ANSWER = :V_ID_ANSWER;
V_NUM = V_NUM + 1;
END
OUT_SUCCESS = 1;
SUSPEND;
END^
SET TERM ; ^
## Script (Python) "Action_create"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
request = container.REQUEST
RESPONSE = request.RESPONSE
""" Здесь мы сохраняем параматры """
if ( request.get('save')):
id_test = request.get('id_test')
id_query = request.get('id_quest')
var1 = request.get('q1','')
var2 = request.get('q2','')
var3 = request.get('q3','')
var4 = request.get('q4','')
var5 = request.get('q5','')
score1 = request.get('s1','')
score2 = request.get('s2','')
score3 = request.get('s3','')
score4 = request.get('s4','')
score5 = request.get('s5','')
correct1 = request.get('c1','')
correct2 = request.get('c2','')
correct3 = request.get('c3','')
correct4 = request.get('c4','')
correct5 = request.get('c5','')
sav = container.save_query(id_query = id_query, query_text = request.get('quest_name','') , t1=var1, t2=var2, t3=var3, t4 = var5, t5=var5, cor1=correct1, cor2=correct2, cor3 = correct3, cor4 = correct4, cor5 = correct5, score1 = score1, score2 = score2, score3 = score3, score4=score4 , score5= score5)
return RESPONSE.redirect('create?id_session=%s&id_test=%s&id_quest=%s' %(request.get('id_session','' ), request.get('id_test',''), request.get('id_quest','') ))
""" Добавляем новыйй незаполненный вариант """
if ( request.get('add')):
container.ADD_VARIANT(id_quest=(request.get('id_quest','')))
return RESPONSE.redirect('create?id_session=%s&id_test=%s&id_quest=%s' %(request.get('id_session','' ), request.get('id_test',''), request.get('id_quest','') ))
""" Добавляем новый вопрос пока без вариантов """
if ( request.get('new')):
add_query = container.ADD_QUERY(id_test=request.get('id_test',''))
return RESPONSE.redirect('create?id_session=%s&id_test=%s&id_quest=%s' %(request.get('id_session','' ), request.get('id_test',''), add_query[0].OUT_ID_QUERY ))
ADD_QUERY
<params>id_test</params>
select * from W_ADD_QUERY(<dtml-sqlvar id_test type="int">)
ADD_VARIANT
<params>id_quest</params>
SELECT * from ADD_VARIANT (
<dtml-sqlvar id_quest type="int" optional >,
null,
0,
0)
create
<html>
<head>
<title>
The title
</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body bgcolor=#faeedd >
<table width=95% align="center" border=1 style="background-color:#F0FFF0" >
<tr>
<td>
<p align="center" ><font size="6">Система мониторинга уровня знаний - "СМУЗ"</font> </p>
<form action="Action_create">
<input type="hidden" name="id_test" id="id_test" tal:attributes="value request/id_test">
<input type="hidden" name="id_quest" id="id_quest" tal:attributes="value request/id_quest|nothing">
<input type="hidden" name="id_questtype" id="id_questtype" tal:attributes="value request/id_questtype|nothing">
<table width=100%>
<tr>
<td width="20%" style="vertical-align: top;">
<DIV style="background:yellow " >
<B> ВОПРОСЫ </B><br>
<span tal:condition="python: request.get('id_test')"
tal:define="list python: container.REP_GET_QUESTION_LIST(id_test=request.get('id_test'))">
<span tal:repeat="item list">
<a tal:content="python: str(item.OUT_QUESTION_DESCRIPTION)"
tal:attributes="href python: 'create?id_quest='+ str(item.OUT_ID_QUESTION) +'&id_test=' + str(item.OUT_ID_TEST) ">
</a><br>
</span>
</span>
<br>
<input type="submit" name="new" value="Добавить вопрос"><br><br>
<!-- ТУТ БУДЕТ ШАБЛОН -->
</DIV>
</td>
<td width="80%" style=" vertical-align: top;">
<DIV style="background:#FFF ">
<B> РЕДАКТОР ВОПРОСОВ</B>
<!-- И ТУТ ТОЖЕ --><BR><BR>
<span tal:repeat="item python: container.SQL_QUEST_TYPE()">
<input type="radio" name="type" tal:attributes="id item/ID_QUERY_TYPE"> <span tal:content="item/NAME" /> <br>
</span>
<hr><br >
Вопрос: <br>
<textarea id="quest_name" name="quest_name" tal:content="python: container.SQL_QUERY_TEXT(id_quest= request.get('id_quest',''))[0].TEXT" >
</textarea> <br>
<span tal:repeat="item python: container.REP_GET_VARIANT(id_quest= request.get('id_quest',''))">
<input type="text" tal:attributes="id python: 'q' + str(item.out_number) ;name python: 'q' + str(item.out_number); value python: item.OUT_TEXT">
<input type="text" size=4 tal:attributes="id python: 's' + str(item.out_number) ;name python: 's' + str(item.out_number); value python: item.OUT_SCORE" >
<input type="checkbox" tal:attributes="id python: 'c' + str(item.out_number) ;name python: 'c' + str(item.out_number); checked python: item.OUT_IS_CORRECT">
<br>
</span>
<input type="submit" name="add" value="+"><br><br>
<input type="submit" name="save" value="Сохранить">
</DIV>
</td></tr>
</table>
<br>
</form>
</td>
</tr>
</table>
</body>
</html>
REP_GET_QUESTION_LIST
<params>id_test</params>
select *
from REP_GET_QUESTION_LIST(<dtml-sqlvar id_test type="int"optional >)
REP_GET_VARIANT
<params>id_quest</params>
select * from REP_GET_VARIANT (<dtml-sqlvar id_quest type="int" optional >)
SAVE_QUERY
<params>id_query query_text t1 t2 t3 t4 t5 cor1 cor2 cor3 cor4 cor5 score1 score2 score3 score4 score5</params>
select * from W_SAVE_QUERY
( <dtml-sqlvar id_query type="int" >,
<dtml-sqlvar query_text type="string" optional >,
<dtml-sqlvar t1 type="string" optional >,
<dtml-sqlvar t2 type="string" optional >,
<dtml-sqlvar t3 type="string" optional >,
<dtml-sqlvar t4 type="string" optional >,
<dtml-sqlvar t5 type="string" optional >,
<dtml-sqlvar cor1 type="string" optional >,
<dtml-sqlvar cor2 type="string" optional >,
<dtml-sqlvar cor3 type="string" optional >,
<dtml-sqlvar cor4 type="string" optional >,
<dtml-sqlvar cor5 type="string" optional >,
<dtml-sqlvar score1 type="float" optional >,
<dtml-sqlvar score2 type="float" optional >,
<dtml-sqlvar score3 type="float" optional >,
<dtml-sqlvar score4 type="float" optional >,
<dtml-sqlvar score5 type="float" optional >)
SQL_QUERY_TEXT
<params>id_quest</params>
select text from REP_GET_QUERY_TEXT (<dtml-sqlvar id_quest type="int" optional >)
SQL_QUEST_TYPE
<params></params>
select * from s_QUery_TYPE
LOGIN
<html>
<head>
<title tal:content="template/title">
Добро пожаловать в СМУЗ
</title>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</head>
<body bgcolor=#faeedd >
<form action="Login_action" >
<table align="center" border=0 style="background-color:#F0FFF0" >
<tr>
<td>
<br>
<p align="center" style="background-color:#white" >
<font size="7">
Система мониторинга уровня знаний
</font>
</p>
<br>
<span tal:condition="python: options.get('err', '')">
<p align="center" style="background-color:#FF0000"> <b> <font size=4 color=#FFFFFF > <span tal:content="python: options.get('err','')"/>
</font> </b> </p>
</span>
Login: <br>
<input type="text" id="login" name="login"> <br>
Password:<br>
<input type="password" id="passw" name="passw" ><br>
<pre> <input type="submit" value="Войти"></pre>
</td>
</tr>
<tr>
<td>
<a href="add_user">
Зарегистрироваться
</a >
</td>
</tr>
</table>
</form>
</body>
</html>
LOGIN_ACTION
## Script (Python) "Login_action"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=
##title=
##
request = container.REQUEST
RESPONSE = request.RESPONSE
login= request.get('login','')
password = request.get('passw','')
if (login==''):
return container.Login(err='Вы не ввели логин')
elif (password==''):
return container.Login(err='Вы не ввели пароль')
else:
log = container.P_LOGIN(login=login, password=password)[0]
if (log.OUT_SUCCESS=='1'):
return RESPONSE.redirect('Iface?id_session=%s' % (log.OUT_ID_SESSION))
else:
return container.Login(err = log.OUT_MESSAGE)
Парсер для Zexp файлов
#!/usr/bin/python
from cStringIO import StringIO
from pickle import Pickler, Unpickler
from struct import pack, unpack
class Dummy:
def __call__(self,*a,**b):
print '-->',self.__dict__['xmodule'], '>>call', a,b
self.__dict__['xmodule']=self.__dict__['xmodule']+(', instance(%s,%s)' % (a,b))
return self
def __setattr__(self,name,value):
print '-->',self.__dict__['xmodule'], 'setattr', name,value
def __getattr__(self,name):
print '-->',self.__dict__['xmodule'], 'getattr', name
def __repr__(self):
return self.__dict__['xmodule']
class Dummy2:
def __init__(self,*a,**b):
#print a,b
self.argmt=[a,b]
def __repr__(self):
return '<%s dict=%s>' % (self.__class__.__name__, self.__dict__)
class CustomUnpickler(Unpickler):
def find_class(self, module, name):
#print '>>find_class', module,name
clname=('%s.%s' % (module,name)).replace('.','_')
exec('class %s(Dummy2):pass' % clname)
return eval(clname)
cls=Dummy()
cls.__dict__['xmodule']='%s.%s' % (module,name)
return cls
_oid = '\0'*8
def FileToNodes(fpath):
#Copyright (c) Zope
f=file(fpath,'rb')
f.read(4)
oids = {}
export_end_marker = '\377'*16
def new_oid():
global _oid
last = _oid
d = ord(last[-1])
if d < 255: # fast path for the usual case
last = last[:-1] + chr(d+1)
else: # there's a carry out of the last byte
last_as_long, = unpack(">Q", last)
last = pack(">Q", last_as_long + 1)
_oid = last
return last
def u64(v):
"""Unpack an 8-byte string into a 64-bit long integer."""
return unpack(">Q", v)[0]
class Ghost(object):
__slots__ = ("oid",)
def __init__(self, oid):
self.oid = oid
def __repr__(self):
return '<%s dict=%s>' % (self.__class__.__name__, self.oid)
def persistent_id(obj):
if isinstance(obj, Ghost):
return obj.oid
def persistent_load(ooid):
"""Remap a persistent id to a new ID and create a ghost for it."""
klass = None
if isinstance(ooid, tuple):
ooid, klass = ooid
if ooid in oids:
oid = oids[ooid]
else:
if klass is None:
oid = new_oid()
else:
oid = new_oid(), klass
oids[ooid] = oid
return Ghost(oid)
out=[]
while 1:
h = f.read(16)
if h == export_end_marker:
break
if len(h) != 16:
raise Exception("Truncated export file")
l = u64(h[8:16])
p = f.read(l)
if len(p) != l:
raise Exception("Truncated export file")
ooid = h[:8]
if oids:
oid = oids[ooid]
if isinstance(oid, tuple):
oid = oid[0]
else:
oids[ooid] = oid = new_oid()
pfile = StringIO(p)
unpickler = CustomUnpickler(pfile)
unpickler.persistent_load = persistent_load
a=unpickler.load()
b=unpickler.load()
#
out.append([oid,a,b])
return out
def make_filelist(node,path,flist,index):
objs=node.get('_objects',[])
xobjs={}
for i in objs:
xobjs[i['id']]=i['meta_type']
keys=xobjs.keys()
keys.sort()
for i in keys:
oid=node[i].oid
if xobjs[i] in ('Folder','Folder (Ordered)'):
flist=make_filelist(index[oid],path+[i],flist,index)
flist.append({'node':index[oid],'path':path+[i],'meta_type':xobjs[i]})
return flist
def parseZobj(objs):
index={}
for i in objs:
index[i[0]]=i[2]
root=objs[0][2]
flist=make_filelist(root,[root['id']],[],index)
out=""
for item in flist:
out+='%s(%s):\n\n' % ('/'.join(item['path']),item['meta_type'])
if item['meta_type']=='File':
out+=item['node']['data']
elif item['meta_type']=='Script (Python)':
out+='params:%s\n' % item['node'].get('_params','')
out+=item['node']['_body']
elif item['meta_type']=='Page Template':
out+=item['node']['_text']
elif item['meta_type']=='Z SQL Method':
out+='params:%s\n' % item['node']['arguments_src']
out+= item['node']['src']
out+='\n\n'
return out
def get_plain_content(fpath):
""" return content of zexp-file """
objs = FileToNodes(fpath)
return parseZobj(objs)
def compareRevisions(fpath,r1,r2):
import os,tempfile
x, fileR1 = tempfile.mkstemp()
x, fileR2 = tempfile.mkstemp()
#print fileR1,fileR2
os.system('svn cat \'%s\'@%s > %s' % (fpath,r1,fileR1))
os.system('svn cat \'%s\'@%s > %s' % (fpath,r2,fileR2))
x, out1 = tempfile.mkstemp()
x, out2 = tempfile.mkstemp()
#print out1,out2
file(out1,'wb').write(get_plain_content(fileR1))
file(out2,'wb').write(get_plain_content(fileR2))
os.system('C:\Program Files\KDiff3\kdiff3.exe %s %s' % (out1,out2))
os.remove(fileR1)
os.remove(fileR2)
os.remove(out1)
os.remove(out2)
def compare_files(path1,path2):
import os,tempfile
x, out1 = tempfile.mkstemp()
x, out2 = tempfile.mkstemp()
file(out1,'wb').write(get_plain_content(path1))
file(out2,'wb').write(get_plain_content(path2))
os.system('"C:\Program Files\KDiff3\kdiff3.exe" %s %s' % (out1,out2))
os.remove(out1)
os.remove(out2)
if __name__=='__main__':
import sys
if len(sys.argv)==1:
print 'Usage: %s COMMAND [ARGUMENTS]' % __file__
print 'Available commands:\n\t compare_svn - compare revisions zexp file\n\t compare_file - compare files'
sys.exit(1)
command=sys.argv[1]
if command == 'compare_svn':
if len(sys.argv)!=5:
print 'Usage: %s %s FILEPATH REVISION1 REVISION2' % (__file__, command)
else:
compareRevisions(sys.argv[2],sys.argv[3],sys.argv[4])
elif command == 'compare_file':
if len(sys.argv)!=4:
print 'Usage: %s %s FILEPATH1 FILEPATH2' % (__file__, command)
else:
compare_files(sys.argv[2],sys.argv[3])