Создание системы мониторинга уровня знаний

  • Вид работы:
    Дипломная (ВКР)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    820,08 Кб
  • Опубликовано:
    2013-11-10
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Создание системы мониторинга уровня знаний

Министерство образования и науки Российской Федерации

Федеральное государственное бюджетное образовательное учреждение высшего профессионального образования

Кубанский государственный университет

ФГБОУ ВПО «КубГУ

Физико-технический факультет

Кафедра теоретической физики и компьютерных технологий

Специальность 230201 - Информационные системы и технологии




ДИПЛОМНАЯ РАБОТА

Создание системы мониторинга уровня знаний




Работу выполнил Елькин М.Н.

Научный руководитель Значко В.Н.





Краснодар 2013

РЕФЕРАТ

Елькин М.Н. Создание системы мониторинга уровня знаний. Дипломная работа: 32 с., 11 рис., 13 источников, 1 приложение.

Системы создания и прохождения тестов, системы управления базами данных, web-сервер

Объектом разработки дипломной работы является система, предназначенная для сбора данных о результатах тестирования, состоящая из модулей создания и прохождения тестов, модуля назначения и модуля просмотра статистики.

Целью работы является разработка системы, способной хранить и обрабатывать большие объемы статистических данных с результатами тестов.

В результате выполнения дипломной работы спроектирована и разработана база данных для хранения статистики. Так же разработаны модули прохождения и создания тестов, и модуль просмотра статистических данных по результатам тестирования.

СОДЕРЖАНИЕ

Введение

. Постановка задачи. Анализ существующих решений

.1 Постановка задачи

.2 Анализ существующих решений

.2.1 UniTest System 4

.2.2 MyTest

.2.3 Moodle

.3 Требования к создаваемой системе

. Выбор и обоснование решения

.1 Описание общей архитектуры системы

. Описание инструментов и методов реализации

.1 Конвенции программирования для системы

.2 Конвенции разработки Firebird

.3 Конвенции разработки ZOPE

.4 Описание архитектуры базы

.5 Методы разработки веб-интерфейсов

.6 Обработка данных при помощи python скриптов

.7 Создание хранимых процедур в Firebid27

. Описание интерфейса разработанной системы

.1 Модуль создания тестов

.2 Модуль прохождения тестов

.3 Модуль назначения тестов

.4 Модуль просмотра статистики

Заключение

Список используемых источников

Приложение А Исходный код системы

ВВЕДЕНИЕ


Системы, используемые для создания и прохождения тестов, обладают отличными инструментами для создания и прохождения созданных тестов. Но сбор статистики в таких системах является дополнительным функционалом, возможности которого не развиваются.

Целью работы является создание системы мониторинга уровня знаний, которая позволит собирать статистические данные по результатам тестирований. Использование системы позволит получать расширенные наборы обработанных статистических данных, и применять к ним методы системного анализа.

Работа содержит описание и анализ существующих систем для мониторинга уровня знаний. Так же в работе присутствует обоснование архитектурного решения, для разрабатываемой системы, и само решение, краткое описание инструментов разработки. В работе описана структура приложения, а так же основные приемы программирования используемые при реализации системы.

1. ПОСТАНОВКА ЗАДАЧИ. АНАЛИЗ СУЩЕСТВУЮЩИХ РЕШЕНИЙ

 

.1 Постановка задачи


Сейчас существует множество программ для создания и прохождения тестов, но большинство из них не обладает полноценными инструментами по сбору, хранению, и обработке статистики, полученной при прохождении тестов.

Создание системы мониторинга уровня знаний позволит собирать подробную статистику по результатам тестирований студентов за длительный период. Помимо основных статистических данных, таких как результат тестирования и время затраченное на прохождение теста, система будет содержать данные, о времени ответа на каждый вопрос, средние баллы получаемые за тест и процент правильных ответов на вопрос. Все вопросы и тесты в базе будут разбиты по тематике, что позволит при анализе результатов эффективно выделять темы с которыми у учащихся возникают проблемы. При использовании такой системы длительное время на основе собранных ею данных, можно проводить анализ уровня подготовки студентов разных годов выпуска.

Система состоит из четырех основных модулей.

·  Модуля для создания и редактирования тестов.

·        Модуля для назначения тестов учащимся.

·        Модуля прохождения тестов.

·        Модуля получения статистики по результатам тестов.

1.2 Анализ существующих решений


Сейчас на рынке программного обеспечения существует множество программных продуктов для мониторинга уровня знаний с различной архитектурой и сферой применения. Для анализа выберем три наиболее распространенные системы, такие как UniTest System 4, MyTest, Moodle. И подробнее познакомимся с этими системами.

 

.2.1 UniTest System 4

UniTest System 4 решение для создания компьютерных тестов, проведения тестирования (как локально, так и по сети), детального анализа результатов тестирований и составления отчетов.

Система состоит из нескольких утилит Editor, Monitor, Report, Setting, Test.

Утилита Editor предназначен для создания и редактирования тестов, используемых для проведения тестирований в утилите Test. [1]

Утилита Test предназначена для прохождения тестов в созданных через утилиту Editor.

Утилита Report служит для получения информации по тестам, на рисунке 1 показан пример отчета созданного через Reporter

Утилита Monitor предназначен для администрирования и мониторинга процесса тестирования в сетевой версии пакета. В сетевой версии утилиты Test являются клиентами, которые подключаются к утилите Monitor и через нее проводят тестирование. Monitor контролирует все действия Test'ов и может разрешать или запрещать подключение отдельных клиентов (Test'ов) или целых групп, отключать или блокировать подключение уже подключенных клиентов. По каждому подключенному клиенту можно посмотреть подробную информацию (статус подключения, информация о тестируемом и о состоянии тестирования на текущий момент).позволяют настроить работу пакета UniTest System в целом и его отдельных компонентов. Можно установить пути к базам данных собст, используемым по умолчанию, и указать пароли к ним. Можно задать поля ввода данных о тестируемом, которые будут отображаться при тестировании. Здесь же можно настроить разбалловку тестов и внешний вид Test. [1]

Недостатком системы является хранение данных бинарном файле, что замедляет доступ к ним при работе с большими объемами данных, также это делает невозможным получение группированных по различным параметрам данных. Так же недостатком является отсутствие целостности статистики. Каждый запущенный модуль Monitor пишет информацию в свой отдельный файл, который в дальнейшем придется компоновать с другими файлами результатов, для получения целостной картины. В противном случае это означает, что модуль Monitor одновременно может быть запущен только на одном компьютере и что только один человек сможет быть администратором.

Рисунок 1 - Пример созданного отчета в системе UniTest System через модуль Reporter

 

.2.2 MyTest

MyTest система программ для создания и проведения компьютерного тестирования, сбора и анализа их результатов, аналогичная UniTest System 4 состоит из трех модулей: Модуль тестирования (MyTestStudent), Редактор тестов (MyTestEditor) и Журнал тестирования (MyTestServer).

Редактор тестов (MyTestEditor) модуль для создания и редактирования тестов, для каждого теста создается бинарный файл

Модуль тестирования (MyTestStudent) предназначен для работы с бинарными файлами, созданными в редакторе тестов.

Журнал тестирования (MyTestServer) модуль программы MyTest, позволяющий централизовано принимать и обрабатывать результаты тестирования, раздавать тесты посредством компьютерной сети. Для отправки и получения результатов, отправки файлов с тестами используется протокол Интернета TCP/IP. На рисунке 2 форма для просмотра результатов в журнале тестирования MyTestServer.

Недостатком системы является хранение данных бинарном файле, что замедляет доступ к ним при работе с большими объемами данных, также это делает невозможным получение группированных по различным параметрам данных. Так же недостатком является отсутствие целостности статистики. Каждый запущенный модуль Monitor пишет информацию в свой отдельный файл, который в дальнейшем придется компоновать с другими файлами результатов, для получения целостной картины. В противном случае это означает, что модуль Monitor одновременно может быть запущен только на одном компьютере и что только один человек сможет быть администратором.

Рисунок 2 - Результаты тестов в MyTestServer

1.2.3 Moodle

Moodle - система управления курсами (электронное обучение), также известная как система управления обучением или виртуальная обучающая среда. Представляет собой свободное (распространяющееся по лицензии GNU GPL) веб-приложение, предоставляющее возможность создавать сайты для онлайн-обучения. [7]

В Moodle так же есть возможность создавать тесты и получать статистику. При прохождении тестов статистика пишется в подключенную СУБД, но записываются не весь набор данных, который нас интересует. Так же у Moodle сложный, относительно других рассмотренных систем, процесс создания тестов. На рисунке 3 изображен модуль отчетов moodle

Рисунок 3 - Модуль отчета в moodle

1.3 Требования к создаваемой системе


После анализа существующих систем можно сделать вывод о том, какими свойствами должна обладать создаваемая система.

1. Кроссплатформенность. Система должна работать под управлением с различных ОС. И не должны вызывать сложностей для работы с системой с различных устройств.

2.       Работа по сети. Система должна поддерживать работу с сетью, для сбора всех данных в единственный банк данных, так позволит работать в системе удаленно, к примеру, находясь у себя дома.

.        Совместимость с уже используемой в КубГУ системой Moodle. Система должна быть легко встраиваемой в существующую архитектуру и не должна вызывать дополнительных затрат на интеграцию.

.        Обеспечение быстрого доступа к статистическим данным. Для хранения и получения данных следует использовать СУБД, что позволит хранить и обрабатывать большие объемы данных.

.        Обеспечение безопасности доступа к данным.

2. ВЫБОР И ОБОСНОВАНИЕ РЕШЕНИЯ


Рассмотрим подробнее способы достижения требований изложенных в прошлой главе. Первые три пункта кроссплатформенность, работу по сети и совместимость с moodle можно выполнить, реализовав систему в виде web-приложение. Система будет доступна с любого устройства, у которого есть доступ к сети. Для четвертого пункта необходимо выбрать СУБД. Среди некоммерческих СУБД, можно выделить две это PostgreSQL и Firebird. Для своей системы я выбирал Firebird т.к. это простая в эксплуатации и разработке СУБД.

Firebird - реляционная СУДБ, обладает многоверсионной архитектурой, обеспечивающей параллельную обработку оперативных и аналитических запросов (это возможно потому, что читающие пользователи не блокируют пишущих), компактность (дистрибутив 5Mb), высокую эффективность и мощную языковую поддержку для хранимых процедур и триггеров. [3][4] СУДБ легко работает с большими базами данных. Среди минусов можно отметить отсутствие кеша результатов запросов и отсутствие полнотекстовых индексов.

Основные характеристики Firebird

·  Полная подержка хранимых процедур и триггеров.

·        Транзакции, полностью совместимые с концепцией ACID.

·        Ссылочная целостность.

·        Версионная архитектура.

·        Очень небольшой размер.

·        Мощный внутренний язык для написания хранимых процедур и триггеров (PSQL).

·        Поддержка внешних пользовательских функций (UDF).

·        Firebird практически не требует работы системного администратора или позволяет свести ее к минимуму.

·        Почти не требует настройки - использовать СУБД можно сразу же после ее установки!

·        Огромное интернет-сообщество пользователей и разработчиков, множество мест, где вы можете получить быструю и бесплатную помощь.

·        Возможность распространения встроенной в приложение (embedded) версии - замечательно подходит для создания каталогов на CD-ROM, однопользовательских и пробных версий программ.

·        Десятки специализированных приложений от сторонних разработчиков, включая средства администрирования, репликации, и так далее.

·        Безопасная запись данных (careful write) - быстрое восстановление после сбоев, отсутствие необходимости в журналировании транзакций!

·        Большое количество средств доступа к базе данных: native/API, драйверы dbExpress, ODBC, OLEDB, .Net provider, JDBC-драйвер, модули для Python, PHP, Perl, и так далее.

·        Поддержка большинства распространенных операционных систем, включая Windows, Linux, Solaris, MacOS.

·        Инкрементные бэкапы

·        Билды для 32- и 64-разрядных ОС

·        Полная реализация курсоров в PSQL

·        Таблицы мониторинга

·        Триггеры на коннект и транзакции

·        Временные таблицы [9]

В качестве web-сервера будет использоваться Zope 2, это объектно-ориентированная платформа, сервер приложений, написанный на языке python, предназначенный для создания динамических web-приложений и интерактивных сайтов.

Он был выбран мной в качестве web-сервера так как протоколы WWW (HTTP, CGI и т.д.) часто неадекватны задачам и могут делать публикацию динамических данных неоправданно сложной. Их низкий уровень недостаточен для непосредственного создания многих классов web-приложений на их основе. Zope создает объектно-ориентированную оболочку вокруг этих низкоуровневых средств. С его помощью решение задачи происходит обычным путем - программист пишет набор иерархий классов, являющийся абстракцией предметной области, а Zope берет на себя труд по предоставлению доступа к экземплярам этих классов. [5]предоставляет программистам и администраторам простые, и в то же время мощные и гибкие механизмы управления безопасностью. Безопасность в Zope стоит на трех китах, трех базовых понятиях - пользователь, роль, и вид доступа, что удовлетворяет последнему пункту требований.

Вид, или тип доступа определяет программист при создании компонента. Каждому классу в компоненте определяется полномочие "Add" ("Добавить экземпляр класса в дерево объектов"), каждому методу класса можно определить свои собственные полномочия, которые определят, кому и какой вид доступа предоставлен к этому методу класса. Например, методу index_html (который вызывается при обращении к объекту, а не к конкретному методу) обычно дается вид доступа View. Но это дело программиста, как назвать свои полномочия, и какие методы какими полномочиями защитить. Обычно методы объекта объединяются в группы, предоставляющие один сервис. Например, класс Новостная Лента может иметь сервисы (группы методов) "показ новостей", "добавление новостей", "редактирование новостей", "удаление новостей", "добавление/редактирование/удаление рубрик". И каждый из сервисов можно защитить (дав ему отдельный вид доступа) - с точностью до одного метода. Для более тонкого управления, уже внутри метода, программист может запросить Security Manager - "имеет ли текущий пользователь права на создание DTML Методов в Папке Razdel?"

Роли создает администратор сайта через менеджерский web-интерфейс Zope. Понятие роли распространяется не на весь сайт, не на ZODB, а на часть дерева. Администратор создает роль в какой-то папке, и дальше благодаря механизму acquisition эта роль распространяется вниз по поддереву., поставленная из дистрибутива, имеет 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 обычно читаемый и понятный (например, по сравнению с Perl). [10]

Для динамического построения страниц из шаблонов в Zope применяется язык TALявляется системой шаблонов Zope Page Template (ZPT). TAL поддерживает пространства имен TAL, METAL и I18N.является эквивалентом TALES, Template Attribute Language Expression Syntax (синтаксис атрибутивного языка шаблонов). Он определяет, как обрабатываются значения атрибутов XML.

Так как PTALES подобен TALES, TAL шаблоны python и PHP могут одинаково использоваться и транспортироваться из одного языка в другой.

Чтобы быть совместимым с PHPTAL, TAL реализует XPath-подобный доступ к данным. [6]

Для подключения к Firebird используется продукт kinterbasDA. Продукты - компоненты, написанные программистом на Питоне - позволяют дополнять Zope новыми типами объектов. В нашем случае это драйвер для работы с СУБД. Он позволяет создавать параметризированные SQL методы. Вызывать методы можно непосредственно на странице, используя TAL шаблон, или в скрипте, написанном на языке Python.

 

.1 Описание общей архитектуры системы


Система состоит из формы авторизации и четырех модулей.

·  Модуль создания тестов

·        Модуль назначения тестов

·        Модуль прохождения тестов

·        Модуль просмотра статистики

Каждый из модулей использует свой собственный коннект под отделенной для модуля ролью, с определенным набором прав и разрешений.

На следующем рисунке представлено схематическое строение модулей.

Рисунок 4 - Общая архитектура модулей

Архитектура всех модулей однотипная, модуль состоит из одного или нескольких форм-шаблонов, передающих данные скриптам, написанным на языке python. Скрипты обрабатывают данные, после чего обращаются в базу, вызывая хранимые процедуры, в которых содержится логика модуля. В зависимости от результатов возвращаемых из базы в скрипте принимается решение о переходе на ту или иную форму. Данные для формы так же подгружаются из базы.

3. ОПИСАНИЕ ИНСТРУМЕНТОВ И МЕТОДОВ РЕАЛИЗАЦИИ

 

.1 Конвенции программирования для системы


В высококачественном программировании должна быть очевидна связь между концептуальной целостностью архитектуры и её низкоуровневой реализации. Реализация должна соответствовать высокоуровневой архитектуре и обладать внутренней согласованностью. В этом заключается смысл принципов конструирования, определяющих конвенции именования переменных, классов, методов, а так еж форматирования кола и оформления переменных.

При разработке сложной программы архитектурные принципы вносят в программу структурный баланс, а принципы конструирования - низкоуровневую гармонию, при наличии которой каждый класс определяется как неотъемлемая часть общего плана. Любая крупная программа требует применения контролирующей структуры, унифицирующей аспекты языка программирования. Красота крупной структуры частично заключается в том, как в её отдельных компонентах выражены особенности архитектуры. Без унификации программа будет смесью небрежных вариаций стиля, заставляющих прилагать дополнительные усилия только для того, чтобы различия в стиле кодирования, которые вполне можно было избежать. Одно из условий успешного программирования - устранение ненужных вариаций, позволяющее сосредоточиться на днйствительно необходимых вариациях. [11]

3.2 Конвенции разработки Firebird


1. Имена всех объектов должны отражать способ их использования.

.1 Имена генераторов состоят из буквы «G» нижнего подчеркивания и наименования первичного ключа для генерации чьего значения используется генератор. Имена генераторов используемых для других целей начинаются с «GEN_» далее используется любое имя отражающее назначение генератора.

1.2     Имена триггеров имею формат «TR_<ИМЯ_ТАБЛИЦЫ>_<Время срабатывания>_<Доплнительная_информация>». Где Время срабатывания буквы BI (перед вставкой), AI (после вставки), BU(до обновления), AU(после обновления), BD(до удалени), AD(после удаления).

.3       Имена таблиц, используемых для хранения данных, начинаются с префикса «S_», тем самым обозначая, что таблицы используются для статического хранения данных. Таблицы, используемые для хранения справочников, маркируются префиксом «L_». Таблицы, хранящие часто изменяемые данные, обозначаются префиксом «D_».

.4       Имена хранимых процедур начинаются с префиксов «REP_» и «W_».

1. Префикс «REP_» обозначает, что процедура производит лишь чтение данных. Префиксом «W_» маркируются процедуры производящие изменения в БД.

2.       Типы данных в таблицах описываются строго прописанными доменами.

.        Записи из таблиц не удаляются, для пометки записи как удаленная используется поле статус, которое заполняется подходящим значением из таблицы статусов записей.

.        В каждой таблице в качестве первичного ключа используется целочисленное поле.

.        В каждой таблице существуют два поля, хранящие информацию о дате последнего изменения записи и о пользователе, который последним производил изменение, поля имеют фиксированные имена LASTDATE и USRNAME.

.        Всем триггерам, работающим с одной таблицей и имеющим одинаковое время срабатывания, присваивается уникальный приоритет кратный 100.

.        Наименования входных переменных должно начинаться с префикса «IN_» выходных - «OUT_». Внутренние переменные начинаются с префикса «V_».

 

.3 Конвенции разработки ZOPE


1. Все ZSQL методы должны именоваться как процедуры, которые они вызывают. Если процедура не вызывается, или запрос включает в себя подзапросы или связи то имя метода начинается с префикса «SQL_» после чего следует имя метода, описывающее суть метода.

2.       Каждый шаблон (PageTamplate), кроме шаблонов расположенных в корне, имеет уникальный префикс каталога, в котором он находится, шаблоны из корневого каталога имею префикс «r_».

.        Скрипты языка python, вызываемые по отправке данных с формы должны иметь имя «action_» + <имя формы, с которой был вызван скрипт>. Остальные скрипты должны иметь префикс «S_»

.        Каждый модуль использует свой собственный коннект к базе.

.        Имена переменных передаваемых в скрипт, с формы и наоборот должны совпадать. Однотипность имен позволяет быстрее вести разработку и уменьшает вероятность ошибок, связанных с путаницей в именах переменных.

 

.4 Описание архитектуры базы


База состоит из 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 - Схематическая связь таблиц в базе

 

.5 Методы разработки веб-интерфейсов


Одним из методов создания страниц в Zope является панель администратора Zope (Рисунок 6). Расположенная по адресу #"702316.files/image006.gif">

Рисунок 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.al шаблоны так же позволяют строить динамические списки.

Например построение списка типов вопросов на форме создания тестов (рисунок 9).

Рисунок 9 Список типов вопросов

Код описывающий построение списка.

<span tal:repeat="item python: container.SQL_QUEST_TYPE()">

<input type="radio" name="type" tal:attributes="id /ID_QUESTTYPE"> <span tal:content="item/NAME" /> <br>

</span>

Tal:repeat - конструкция определяющая повторяющийся тег, со всем своим содержимым. Повторяться он будет столько раз, сколько строк вернет Z SQL метод SQL_QUEST_TYPE. Z SQL методы - объекты Zope для создания параметризированных запросов к базе данных.

Пример SQL метода:

OUT_ID_QUESTION, OUT_STATUS, OUT_NUM,_QUESTION_DESCRIPTION, OUT_ID_TESTREP_GET_QUESTION_LIST(<DTML-SQLVAR ID_TEST ="INT"OPTIONAL >)

Запрос вызывающий хранимую процедуру и передающий в неё идентификатор теста для получения списка вопросов по этому тесту.

 

.6 Обработка данных при помощи python скриптов


Рассмотрим обработку данных на примере формы регистрации

Объявим методы request и RESPONSE.

= container.REQUEST = request.RESPONSE

Запросим из полученного набора присланных данных значения полей с логином и паролем

login= request.get('login','')= request.get('passw','')

Удостоверимся, что значения не являются пустыми

if (login==''):

Если значение пустое, то выведем снова форму логина, дополнительно передав на нее сообщение о пустом логине или пароде

return container.Login(err='Вы не ввели логин')(passw==''):container.Login(err='Вы не ввели пароль'):

Если же поля заполнены, то вызываем через параметризованный ZSQL метод процедуру для проверки правильности введенных логина и пароля. Значения возращенные процедурой запишем в переменную log.

log = container.P_LOGIN(login=login, passw=passw)[0]

Если пароль и логин подтвердились, то переходим на форму со списком модулей и передаем на неё идентификатор сессии под которым будет работать пользователь.

if (log.OUT_SUCCESS=='1'):RESPONSE.redirect('Iface?id_session=%s' %

(log.OUT_ID_SESSION)):

Иначе вернемся на форму регистрации с сообщением об ошибке.

return container.Login(err = log.OUT_MESSAGE).

 

3.7 Создание хранимых процедур в Firebid


Для написания процедур используется PSQL - расширение языка SQL для СУБД Firebird. Основными элементами являются циклы и логические операторы.

Каждая процедура состоит из следующих обязательных выражений

Объявление действия совершаемого над процедурой, в скобках перечисляются входные параметры процедуры.

CREATE OR ALTER PROCEDURE PROCEDURE_NAME ()

В конструкции в скобках RETURNS () перечисляются выходные параметры которые будут выведены процедурой после вызова команды SUSPEND. Команды BEGIN и END обозначают конец и начало блока с текстом процедуры. Ниже приведен пример простейшего цикла, который выбирает все варианты ответов по вопросу, присваивая каждому варианту ответа свой номер начиная с одного.

OUT_NUMBER = 0;

Объявляем массив, который будем обрабатывать.

FORla.ID_ANSWER, la.IS_CORRECT, la.TEXT, la.SCOREL_ANSWER lala.ID_QUERY = :IN_QUESTION_NUMBER

Переменные, которым будут присваиваться значения из массива.

INTO :OUt_ID_ANSWER, :OUT_IS_CORRECT, :OUT_TEXT,

:OUT_SCORE

DO BEGIN

Тело цикла с инкрементом счетчика и выводом информации.

OUT_NUMBER = OUT_NUMBER +1;;

END

4. ОПИСАНИЕ ИНТЕРФЕЙСА РАЗРАБОТАННОЙ СИСТЕМЫ

 

.1 Модуль создания тестов


Модуль создания тестов предназначен для создания новых и редактирования существующих тестов. Модуль состоит из трёх форм, формы выбора теста для редактирования, непосредственно формы редактирования и формы создания нового теста. Права на модуль имеют только пользователи, входящие в группу преподавателей. Остальные пользователи не имеют возможности зайти в этот модуль. На рисунке 10 изображена форма редактирования тестов, модуля создания тестов.

Рисунок 10 - Форма редактирования теста

4.2 Модуль прохождения тестов


Модуль прохождения тестов предназначен для прохождения тестов. Модуль состоит из двух форм, формы выбора теста для прохождения и формы и непосредственно формы прохождения тестов, подгружающего данные в различном формате, в зависимости от типа вопроса. Права на модуль есть у всех пользователей, а возможностью проходить все тесты без назначения, обладают только пользователи из группы администратор и из группы преподаватели. На рисунке 11 изображен пример интерфейса.

Рисунок 11 - Форма прохождения тестов

 

.3 Модуль назначения тестов


Модуль назначения тестов предназначен для назначения пользователям тестов на прохождение. Состоит из формы со списком пользователей и тестов и формы для просмотра привязанных к пользователю тестов.. Модуль доступен для пользователей из группы администратор и из группы преподаватели.

 

.4 Модуль просмотра статистики


Модуль предназначен для просмотра статистики по пройденным тестам. Модуль доступен всем пользователям, но внутри модуля существуют ограничения на запуск тех или иных отчетов. Модуль состоит из формы со списком отчетов, и множества форм самих отчетов.

модуль тест архитектура интерфейс

ЗАКЛЮЧЕНИЕ


Основные результаты работы состоят в следующем:

) Проведен анализ существующих систем для тестирования и сбора результатов. Выявлены достоинства и недостатки каждой из рассмотренных систем.

) На основе анализа существующих систем сформулированы концепции разрабатываемой системы, на основе была спроектирована архитектура разрабатываемой системы.

) Была спроектирована структура базы данных с учетом специфики использования системы, для хранения больших объемов данных.

) Спроектированы интерфейсы для системы мониторинга уровня знаний.

) Разработана система мониторинга уровня знаний учащихся.

) Система может применяться в любых учебных заведениях для сбора статистики по результатам тестов и проведения анализа собранных данных.

СПИСОК ИСПОЛЬЗУЕМЫХ ИСТОЧНИКОВ


1. Основные возможности UniTest System

. MyTest - Компьютерное тестирование знаний UPL

. Firebird: About Firebird 25 января 2013

4. iBase.ru | Firebird 18 марта 2012 URL

. Zope - The Object Publishing Environment URL

. PHPTAL URL

. Moodle.org: open-source community-based tools for learning

. Plone.org.ru: wikipage - Сайт поддержки систем управления сайтами Plone, Zope, языка python 19 августа 2006.

. Узнайте Firebird 23 сентября 2011

Zope uses Python - The Zope 2 Application Server

11 Макконелл С. Совершенный код. Мастер-класс / Пер. с англ. - М.: Русская редакция, 2012 - 896 стр.: ил.

Марк Лутц Изучаем Python. / Пер. с англ. - М.: Символ-Плюс 2011 - 1280 с.

. Хелен Борри. Firebird: руководство разработчика баз данных / Пер. с англ. - СПб «БХВ-Петербург» 2007 - 1104 с.

ПРИЛОЖЕНИЕ А

 

Исходный код системы


/*************************************************************

*****************/

/*** Generated by IBExpert 2012.9.2.1 18.06.2013 23:24:13 ***/

/*************************************************************

*****************/SQL DIALECT 3;NAMES WIN1251;DATABASE '127.0.0.1:C:\Documents and Settings\Admin\Рабочий стол\SMUZ2.FDB''SYSDBA' PASSWORD 'masterkey'_SIZE 16384CHARACTER SET WIN1251;

/******************************************************************************/

/*** Domains ***/

/******************************************************************************/DOMAIN D1024VARCHAR AS(1024);DOMAIN D10CHAR AS(10);DOMAIN D128VARCHAR AS(128);DOMAIN D512VARCHAR AS(512);DOMAIN D60CHAR AS(60);DOMAIN D60VARCHAR AS(60);DOMAIN DATES AS;DOMAIN DOUBLE_PREC ASPRECISION;DOMAIN INTT AS;DOMAIN PRK ASNULL;DOMAIN TIMEST AS;

/******************************************************************************/

/*** Generators ***/

/******************************************************************************/GENERATOR G_ID_ANSWER;GENERATOR G_ID_ANSWER TO 21;GENERATOR G_ID_GROUP;GENERATOR G_ID_GROUP TO 0;GENERATOR G_ID_QUERY;GENERATOR G_ID_QUERY TO 3;GENERATOR G_ID_QUERY_TYPE;GENERATOR G_ID_QUERY_TYPE TO 10;GENERATOR G_ID_RES_ANSWER;GENERATOR G_ID_RES_ANSWER TO 0;GENERATOR G_ID_RES_TEST;GENERATOR G_ID_RES_TEST TO 0;GENERATOR G_ID_SESSION;GENERATOR G_ID_SESSION TO 0;GENERATOR G_ID_TEST;GENERATOR G_ID_TEST TO 1;GENERATOR G_ID_THEM;GENERATOR G_ID_THEM TO 0;GENERATOR G_ID_USER;GENERATOR G_ID_USER TO 0;GENERATOR G_ID_USER_GROUP;GENERATOR G_ID_USER_GROUP TO 0;TERM ^ ;

/******************************************************************************/

/*** Stored Procedures ***/

/******************************************************************************/PROCEDURE ADD_VARIANT (_ID_QUESTION INTEGER,_TEXT VARCHAR(128),_IS_CORRECT INTEGER,_SCORE DOUBLE PRECISION)(INTEGER);^PROCEDURE GENERATE_TRIGGER(_TRIG_TEXT VARCHAR(10000));^PROCEDURE REP_GET_QUERY_TEXT (_ID_QUERY INTEGER)(VARCHAR(512));^PROCEDURE REP_GET_QUESTION_LIST (_ID_TEST INTEGER)(_ID_TEST INTEGER,_ID_QUESTION INTEGER,_NUM INTEGER,_QUESTION_DESCRIPTION VARCHAR(128));^PROCEDURE REP_GET_VARIANT (_QUESTION_NUMBER INTEGER)(_ID_ANSWER INTEGER,_IS_CORRECT INTEGER,_TEXT VARCHAR(128),_SCORE DOUBLE PRECISION,_NUMBER INTEGER,_AUERY_TEXT VARCHAR(512));^PROCEDURE W_ADD_QUERY (_ID_TEST INTEGER)(_ID_QUERY INTEGER);^PROCEDURE W_SAVE_QUERY (_ID_QUERY INTEGER,_QUERY_TEXT VARCHAR(512),_TEXT_1 VARCHAR(128),_TEXT_2 VARCHAR(128),_TEXT_3 VARCHAR(128),_TEXT_4 VARCHAR(128),_TEXT_5 VARCHAR(128),_CORRECT_1 VARCHAR(5),_CORRECT_2 VARCHAR(5),_CORRECT_3 VARCHAR(5),_CORRECT_4 VARCHAR(5),_CORRECT_5 VARCHAR(5),_SCORE_1 DOUBLE PRECISION,_SCORE_2 DOUBLE PRECISION,_SCORE_3 DOUBLE PRECISION,_SCORE_4 DOUBLE PRECISION,_SCORE_5 DOUBLE PRECISION)(_SUCCESS INTEGER,_MESSAGE VARCHAR(128));^TERM ; ^

/******************************************************************************/

/*** Tables ***/

/******************************************************************************/TABLE D_RES_ANSWER (_RES_ANSWER PRK,_RES_TEST INTT,_TEST INTT,_ANSWER INTT,_SESSION INTT,TIMEST,TIMEST,_CORRECT INTT,DOUBLE_PREC,DOUBLE_PREC,INTT,TIMEST,D10CHAR

);TABLE D_RES_TEST (_RES_TEST PRK,_TEST INTT,_SESSION INTT,TIMEST,TIMEST,DOUBLE_PREC,DOUBLE_PREC,INTT,TIMEST,D10CHAR

);TABLE HEL (VARCHAR(100),VARCHAR(100)

);TABLE L_ANSWER (_ANSWER PRK,_QUERY INTT,INTT,D512VARCHAR,_CORRECT INTT,DOUBLE_PREC,INTT,TIMEST,D10CHAR

);TABLE L_GROUP (_GROUP PRK,D128VARCHAR,D10CHAR,_EDIT INTT,_ASSEMBLE INTT,_STAT INTT,_TEST INTT,D1024VARCHAR,INTT,TIMEST,D10CHAR

);TABLE L_QUERY (_QUERY PRK,_QUERY_TYPE INTT,_TEST INTT,_THEM INTT,INTT,D512VARCHAR,INTT,TIMEST,D10CHAR

);TABLE L_SESSION (_SESSION PRK,_USER INTT,TIMEST,TIMEST,INTT,TIMEST,D10CHAR

);TABLE L_TEST (_TEST PRK,_THEM INTT,D128VARCHAR,INTT,TIMEST,D10CHAR

);TABLE L_THEM (_THEM PRK,D128VARCHAR,INTT,TIMEST,D10CHAR

);TABLE L_USER (_USER PRK,D128VARCHAR,D128VARCHAR,D128VARCHAR,INTT,TIMEST,D10CHAR

);TABLE L_USER_GROUP (_USER_GROUP PRK,_USER INTT,_GROUP INTT,INTT,TIMEST,D10CHAR

);TABLE S_QUERY_TYPE (_QUERY_TYPE PRK,D128VARCHAR,D10CHAR,INTT,TIMEST,D10CHAR

);

/******************************************************************************/

/*** Primary Keys ***/

/******************************************************************************/TABLE D_RES_ANSWER ADD CONSTRAINT PK_D_RES_ANSWER PRIMARY KEY (ID_RES_ANSWER);TABLE D_RES_TEST ADD CONSTRAINT PK_D_RES_TEST PRIMARY KEY (ID_RES_TEST);TABLE L_ANSWER ADD CONSTRAINT PK_L_ANSWER PRIMARY KEY (ID_ANSWER);TABLE L_GROUP ADD CONSTRAINT PK_L_GROUP PRIMARY KEY (ID_GROUP);TABLE L_QUERY ADD CONSTRAINT PK_L_QUERY PRIMARY KEY (ID_QUERY);TABLE L_SESSION ADD CONSTRAINT PK_L_SESSION PRIMARY KEY (ID_SESSION);TABLE L_TEST ADD CONSTRAINT PK_L_TEST PRIMARY KEY (ID_TEST);TABLE L_THEM ADD CONSTRAINT PK_L_THEM PRIMARY KEY (ID_THEM);TABLE L_USER ADD CONSTRAINT PK_L_USER PRIMARY KEY (ID_USER);TABLE L_USER_GROUP ADD CONSTRAINT PK_L_USER_GROUP PRIMARY KEY (ID_USER_GROUP);TABLE S_QUERY_TYPE ADD CONSTRAINT PK_S_QUERY_TYPE PRIMARY KEY (ID_QUERY_TYPE);

/******************************************************************************/

/*** Triggers ***/

/******************************************************************************/TERM ^ ;

/******************************************************************************/

/*** Triggers for tables ***/

/******************************************************************************/

/* Trigger: TR_D_RES_ANSWER_BI */TRIGGER TR_D_RES_ANSWER_BI FOR D_RES_ANSWERBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.id_res_answer IS NULL) THENGEN_ID(G_id_res_answer,1)RDB$DATABASE:v_ID;.id_res_answer = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

/* Trigger: TR_D_RES_ANSWER_BU */TRIGGER TR_D_RES_ANSWER_BU FOR D_RES_ANSWERBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_D_RES_TEST_BI */TRIGGER TR_D_RES_TEST_BI FOR D_RES_TESTBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_RES_TEST IS NULL) THENGEN_ID(G_ID_RES_TEST,1)RDB$DATABASE:v_ID;.ID_RES_TEST = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_D_RES_TEST_BU */TRIGGER TR_D_RES_TEST_BU FOR D_RES_TESTBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_ANSWER_BI */TRIGGER TR_L_ANSWER_BI FOR L_ANSWERBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_ANSWER IS NULL) THENGEN_ID(G_ID_ANSWER,1)RDB$DATABASE:v_ID;.ID_ANSWER = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_ANSWER_BU */TRIGGER TR_L_ANSWER_BU FOR L_ANSWERBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_GROUP_BI */TRIGGER TR_L_GROUP_BI FOR L_GROUPBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_GROUP IS NULL) THENGEN_ID(G_ID_GROUP,1)RDB$DATABASE:v_ID;.ID_GROUP = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_GROUP_BU */TRIGGER TR_L_GROUP_BU FOR L_GROUPBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_QUERY_BI */TRIGGER TR_L_QUERY_BI FOR L_QUERYBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_QUERY IS NULL) THENGEN_ID(G_ID_QUERY,1)RDB$DATABASE:v_ID;.ID_QUERY = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_QUERY_BU */TRIGGER TR_L_QUERY_BU FOR L_QUERYBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

/* Trigger: TR_L_SESSION_BI */TRIGGER TR_L_SESSION_BI FOR L_SESSIONBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_SESSION IS NULL) THENGEN_ID(G_ID_SESSION,1)RDB$DATABASE:v_ID;.ID_SESSION = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_SESSION_BU */TRIGGER TR_L_SESSION_BU FOR L_SESSIONBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_TEST_BI */TRIGGER TR_L_TEST_BI FOR L_TESTBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_TEST IS NULL) THENGEN_ID(G_ID_TEST,1)RDB$DATABASE:v_ID;.ID_TEST = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_TEST_BU */TRIGGER TR_L_TEST_BU FOR L_TESTBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_THEM_BI */TRIGGER TR_L_THEM_BI FOR L_THEMBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_THEM IS NULL) THENGEN_ID(G_ID_THEM,1)RDB$DATABASE:v_ID;.ID_THEM = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_THEM_BU */TRIGGER TR_L_THEM_BU FOR L_THEMBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_USER_BI */TRIGGER TR_L_USER_BI FOR L_USERBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_USER IS NULL) THENGEN_ID(G_ID_USER,1)RDB$DATABASE:v_ID;.ID_USER = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_USER_BU */TRIGGER TR_L_USER_BU FOR L_USERBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_USER_GROUP_BI */TRIGGER TR_L_USER_GROUP_BI FOR L_USER_GROUPBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_USER_GROUP IS NULL) THENGEN_ID(G_ID_USER_GROUP,1)RDB$DATABASE:v_ID;.ID_USER_GROUP = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_L_USER_GROUP_BU */TRIGGER TR_L_USER_GROUP_BU FOR L_USER_GROUPBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_S_QUERY_TYPE_BI */TRIGGER TR_S_QUERY_TYPE_BI FOR S_QUERY_TYPEBEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.ID_QUERY_TYPE IS NULL) THENGEN_ID(G_ID_QUERY_TYPE,1)RDB$DATABASE:v_ID;.ID_QUERY_TYPE = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;

^

/* Trigger: TR_S_QUERY_TYPE_BU */TRIGGER TR_S_QUERY_TYPE_BU FOR S_QUERY_TYPEBEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;

^TERM ; ^

/******************************************************************************/

/*** Stored Procedures ***/

/******************************************************************************/TERM ^ ;PROCEDURE ADD_VARIANT (_ID_QUESTION INTEGER,_TEXT VARCHAR(128),_IS_CORRECT INTEGER,_SCORE DOUBLE PRECISION)(INTEGER)(in_ID_QUESTION IS NULL) THEN;(IN_TEXT IS NULL ) THEN IN_TEXT = '';(IN_IS_CORRECT IS NULL) THEN IN_IS_CORRECT = 0;(IN_SCORE IS NULL ) THEN IN_SCORE = 0.0;COUNT(*) FROM L_ANSWER WHERE ID_QUERY = :IN_ID_QUESTIONi;(i<5 ) THENINTO L_ANSWER (ID_QUERY, TEXT,IS_CORRECT, SCORE )(:IN_ID_QUESTION, :IN_TEXT, :IN_IS_CORRECT, :IN_SCORE);;^PROCEDURE GENERATE_TRIGGER(_TRIG_TEXT VARCHAR(10000))VARIABLE V_TAB VARCHAR(50);VARIABLE V_ATR VARCHAR(50);TRIM(TAB), TRIM(ATR)HEL:V_TAB, :V_ATRBEGIN_TRIG_TEXT = 'CREATE OR ALTER TRIGGER TR_'|| V_TAB ||'_BI FOR ' || V_TAB ||

' ACTIVE BEFORE INSERT POSITION 0VARIABLE v_ID integer;(NEW.'|| V_ATR || ' IS NULL) THENGEN_ID(G_'|| V_ATR ||',1)RDB$DATABASE:v_ID;.'|| V_ATR || ' = :V_ID;.lastdate = CURRENT_TIMESTAMP;.username = user;;';STATEMENT :OUT_TRIG_TEXT;;_TRIG_TEXT = 'CREATE OR ALTER TRIGGER TR_'|| V_TAB ||'_BU FOR ' || V_TAB ||

' ACTIVE BEFORE UPDATE POSITION 0.lastdate = CURRENT_TIMESTAMP;.username = user;;';STATEMENT :OUT_TRIG_TEXT;;^PROCEDURE REP_GET_QUERY_TEXT (_ID_QUERY INTEGER)(VARCHAR(512))TEXTL_QUERYID_QUERY = :in_ID_QUERY:text;(:text is null) THEN='';;^PROCEDURE REP_GET_QUESTION_LIST (_ID_TEST INTEGER)(_ID_TEST INTEGER,_ID_QUESTION INTEGER,_NUM INTEGER,_QUESTION_DESCRIPTION VARCHAR(128))

AS

/*получаем по ид-теста список вопросов для прорисовки на странице*/LQ.ID_QUERY, LQ.ID_TEST, LQ.NUM, 'Вопрос № '|| INTTOSTR(LQ.NUM, '%d')

FROM L_QUERY LQLQ.ID_TEST = :IN_ID_TEST:OUT_ID_QUESTION, :OUT_ID_TEST, :OUT_NUM, :OUT_QUESTION_DESCRIPTIONSUSPEND;^PROCEDURE REP_GET_VARIANT (_QUESTION_NUMBER INTEGER)(_ID_ANSWER INTEGER,_IS_CORRECT INTEGER,_TEXT VARCHAR(128),_SCORE DOUBLE PRECISION,_NUMBER INTEGER,_AUERY_TEXT VARCHAR(512))

AS

/*Получаем список вариантов ответа по вопросу*/

SELECT TEXTL_QUERYID_QUERY = :IN_QUESTION_NUMBER:OUT_AUERY_TEXT;_number = 0;la.ID_ANSWER, la.IS_CORRECT, la.TEXT, la.SCOREL_ANSWER lala.ID_QUERY = :IN_QUESTION_NUMBERBY ID_ANSWER:OUt_ID_ANSWER, :OUT_IS_CORRECT, :OUT_TEXT, :OUT_SCOREBEGIN_NUMBER = OUT_NUMBER +1;;^PROCEDURE W_ADD_QUERY (_ID_TEST INTEGER)(_ID_QUERY INTEGER)VARIABLE V_NUM INTEGER;

BEGIN

/*ДОБАВЛЯЕМ ЗАПИСЬ В СПИСОК ВОПРОСОВ ТЕСТА*/

SELECT MAX(Q.NUM)+1L_QUERY QQ.ID_TEST = :IN_ID_TEST:V_NUM;GEN_ID(G_ID_QUERY_TYPE,1)RDB$DATABASE:OUT_ID_QUERY;INTO L_QUERY (ID_QUERY, ID_TEST, NUM)(:OUT_ID_QUERY, :IN_ID_TEST, :V_NUM);;^PROCEDURE W_SAVE_QUERY (_ID_QUERY INTEGER,_QUERY_TEXT VARCHAR(512),_TEXT_1 VARCHAR(128),_TEXT_2 VARCHAR(128),_TEXT_3 VARCHAR(128),_TEXT_4 VARCHAR(128),_TEXT_5 VARCHAR(128),_CORRECT_1 VARCHAR(5),_CORRECT_2 VARCHAR(5),_CORRECT_3 VARCHAR(5),_CORRECT_4 VARCHAR(5),_CORRECT_5 VARCHAR(5),_SCORE_1 DOUBLE PRECISION,_SCORE_2 DOUBLE PRECISION,_SCORE_3 DOUBLE PRECISION,_SCORE_4 DOUBLE PRECISION,_SCORE_5 DOUBLE PRECISION)(_SUCCESS INTEGER,_MESSAGE VARCHAR(128))VARIABLE V_ID_ANSWER INTEGER;VARIABLE V_CORRECT INTEGER;VARIABLE v_num INTEGER;

BEGIN

/*Процедура сохраняет данные с формы*/_MESSAGE = 'Вопрос сохранен.';

FORID_ANSWER, NUML_ANSWERID_QUERY = :IN_ID_QUERYBY NUM:V_ID_ANSWER, :V_NUMBEGIN

/*---------------------------------------------------------------------------*/(V_NUM = 1 ) THEN(IN_TEXT_1 = '') THENFROM L_ANSWERID_ANSWER =:V_ID_ANSWER;(IN_CORRECT_1= 'on')V_CORRECT = 1;V_CORRECT = 0;L_ANSWERTEXT = :IN_TEXT_1,_CORRECT = :V_CORRECT,= :IN_SCORE_1ID_ANSWER =:V_ID_ANSWER;

/*---------------------------------------------------------------------------*/(V_NUM = 2 ) THEN(IN_TEXT_2 = '') THENFROM L_ANSWERID_ANSWER =:V_ID_ANSWER;(IN_CORRECT_2= 'on')V_CORRECT = 1;V_CORRECT = 0;L_ANSWERTEXT = :IN_TEXT_2,_CORRECT = :V_CORRECT,= :IN_SCORE_2ID_ANSWER =:V_ID_ANSWER;

/*---------------------------------------------------------------------------*/(V_NUM = 3 ) THEN(IN_TEXT_3 = '') THENFROM L_ANSWERID_ANSWER =:V_ID_ANSWER;(IN_CORRECT_3= 'on')V_CORRECT = 1;V_CORRECT = 0;L_ANSWERTEXT = :IN_TEXT_3,_CORRECT = :V_CORRECT,= :IN_SCORE_3ID_ANSWER =:V_ID_ANSWER;

/*---------------------------------------------------------------------------*/(V_NUM = 4 ) THEN(IN_TEXT_4 = '') THENFROM L_ANSWERID_ANSWER =:V_ID_ANSWER;(IN_CORRECT_4= 'on')V_CORRECT = 1;V_CORRECT = 0;L_ANSWERTEXT = :IN_TEXT_4,_CORRECT = :V_CORRECT,= :IN_SCORE_4ID_ANSWER =:V_ID_ANSWER;

/*---------------------------------------------------------------------------*/(V_NUM = 5 ) THEN(IN_TEXT_5 = '') THENFROM L_ANSWERID_ANSWER =:V_ID_ANSWER;(IN_CORRECT_5= 'on')V_CORRECT = 1;V_CORRECT = 0;L_ANSWERTEXT = :IN_TEXT_5,_CORRECT = :V_CORRECT,= :IN_SCORE_5ID_ANSWER =:V_ID_ANSWER;

END

/*---------------------------------------------------------------------------*/

/*сохраним текст вопроса*/

IF (C(IN_QUERY_TEXT)='') THENFROM L_QUERYID_QUERY = :IN_ID_QUERY;FROM L_ANSWERID_QUERY = :IN_ID_QUERY;_MESSAGE = 'Вопрос удален.';L_QUERYTEXT = :IN_QUERY_TEXTID_QUERY = :IN_ID_QUERY;

/*исправим нумерацию если её сбили*/

V_NUM = 1;ID_ANSWERL_ANSWERID_QUERY = :IN_ID_QUERYBY NUM:V_ID_ANSWERBEGINL_ANSWERNUM = :V_NUMID_ANSWER = :V_ID_ANSWER;_NUM = V_NUM + 1;_SUCCESS = 1;;^TERM; ^

## Script (Python) "Action_create"

##bind container=container

##bind context=context

##bind namespace=

##bind script=script

##bind subpath=traverse_subpath

##parameters=

##title=

##= container.REQUEST= request.RESPONSE

""" Здесь мы сохраняем параматры """( request.get('save')):

id_test = request.get('id_test')_query = request.get('id_quest')= request.get('q1','')= request.get('q2','')= request.get('q3','')= request.get('q4','')= request.get('q5','')= request.get('s1','')= request.get('s2','')= request.get('s3','')= request.get('s4','')= request.get('s5','')= request.get('c1','')= request.get('c2','')= request.get('c3','')= request.get('c4','')= request.get('c5','')= 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)RESPONSE.redirect('create?id_session=%s&id_test=%s&id_quest=%s' %(request.get('id_session','' ), request.get('id_test',''), request.get('id_quest','') ))

""" Добавляем новыйй незаполненный вариант """( request.get('add')):

container.ADD_VARIANT(id_quest=(request.get('id_quest','')))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')):_query = container.ADD_QUERY(id_test=request.get('id_test',''))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 ))_QUERY

<params>id_test</params>* from W_ADD_QUERY(<dtml-sqlvar id_test type="int">)_VARIANT

<params>id_quest</params>* from ADD_VARIANT (

<dtml-sqlvar id_quest type="int" optional >,,

,

)

<html>

<head>

<title>title

</title>

<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">

</head>

<body bgcolor=#faeedd >

<table 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>

<tr>

<td width="20%" style="vertical-align: top;">

<DIV style="background:yellow " >

<B> ВОПРОСЫ </B><br>

<span tal:condition="python: request.get('id_test')":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)":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>_GET_QUESTION_LIST

<params>id_test</params>*REP_GET_QUESTION_LIST(<dtml-sqlvar id_test type="int"optional >)_GET_VARIANT

<params>id_quest</params>* from REP_GET_VARIANT (<dtml-sqlvar id_quest type="int" optional >)_QUERY

<params>id_query query_text t1 t2 t3 t4 t5 cor1 cor2 cor3 cor4 cor5 score1 score2 score3 score4 score5</params>* 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 >)_QUERY_TEXT

<params>id_quest</params>text from REP_GET_QUERY_TEXT (<dtml-sqlvar id_quest type="int" optional >)_QUEST_TYPE

<params></params>* from s_QUery_TYPE

<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>: <br>

<input type="text" id="login" name="login"> <br>:<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>_ACTION

## Script (Python) "Login_action"

##bind container=container

##bind context=context

##bind namespace=

##bind script=script

##bind subpath=traverse_subpath

##parameters=

##title=

##= container.REQUEST= request.RESPONSE= request.get('login','')= request.get('passw','')(login==''):container.Login(err='Вы не ввели логин')(password==''):container.Login(err='Вы не ввели пароль'):= container.P_LOGIN(login=login, password=password)[0](log.OUT_SUCCESS=='1'):RESPONSE.redirect('Iface?id_session=%s' % (log.OUT_ID_SESSION)):container.Login(err = log.OUT_MESSAGE)

Парсер для Zexp файлов

#!/usr/bin/pythoncStringIO import StringIOpickle import Pickler, Unpicklerstruct import pack, unpackDummy:__call__(self,*a,**b):'-->',self.__dict__['xmodule'], '>>call', a,b.__dict__['xmodule']=self.__dict__['xmodule']+(', instance(%s,%s)' % (a,b))self__setattr__(self,name,value):'-->',self.__dict__['xmodule'], 'setattr', name,value__getattr__(self,name):'-->',self.__dict__['xmodule'], 'getattr', name__repr__(self):self.__dict__['xmodule']Dummy2:__init__(self,*a,**b):

#print a,b.argmt=[a,b]__repr__(self):'<%s dict=%s>' % (self.__class__.__name__, self.__dict__)CustomUnpickler(Unpickler):find_class(self, module, name):

#print '>>find_class', module,name=('%s.%s' % (module,name)).replace('.','_')('class %s(Dummy2):pass' % clname)eval(clname)=Dummy().__dict__['xmodule']='%s.%s' % (module,name)cls

_oid = '\0'*8FileToNodes(fpath):

#Copyright (c) Zope=file(fpath,'rb').read(4)= {}_end_marker = '\377'*16new_oid():_oid= _oid= ord(last[-1])d < 255: # fast path for the usual case= last[:-1] + chr(d+1): # there's a carry out of the last byte_as_long, = unpack(">Q", last)= pack(">Q", last_as_long + 1)

_oid = lastlastu64(v):

"""Unpack an 8-byte string into a 64-bit long integer."""unpack(">Q", v)[0]Ghost(object):

__slots__ = ("oid",)__init__(self, oid):.oid = oid__repr__(self):'<%s dict=%s>' % (self.__class__.__name__, self.oid)persistent_id(obj):isinstance(obj, Ghost):obj.oidpersistent_load(ooid):

"""Remap a persistent id to a new ID and create a ghost for it."""= Noneisinstance(ooid, tuple):, klass = ooidooid in oids:= oids[ooid]:klass is None:= new_oid():= new_oid(), klass[ooid] = oidGhost(oid)=[]1:= f.read(16)h == export_end_marker:len(h) != 16:Exception("Truncated export file")= u64(h[8:16])= f.read(l)len(p) != l:Exception("Truncated export file")= h[:8]oids:= oids[ooid]isinstance(oid, tuple):= oid[0]:[ooid] = oid = new_oid()= StringIO(p)= CustomUnpickler(pfile).persistent_load = persistent_load=unpickler.load()=unpickler.load()

#.append([oid,a,b])outmake_filelist(node,path,flist,index):=node.get('_objects',[])={}i in objs:[i['id']]=i['meta_type']=xobjs.keys().sort()i in keys:=node[i].oidxobjs[i] in ('Folder','Folder (Ordered)'):=make_filelist(index[oid],path+[i],flist,index).append({'node':index[oid],'path':path+[i],'meta_type':xobjs[i]})flistparseZobj(objs):={}i in objs:[i[0]]=i[2]=objs[0][2]=make_filelist(root,[root['id']],[],index)="" for item in flist:+='%s(%s):\n\n' % ('/'.join(item['path']),item['meta_type'])item['meta_type']=='File':+=item['node']['data']item['meta_type']=='Script (Python)':+='params:%s\n' % item['node'].get('_params','')+=item['node']['_body']item['meta_type']=='Page Template':+=item['node']['_text']item['meta_type']=='Z SQL Method':+='params:%s\n' % item['node']['arguments_src']+= item['node']['src']+='\n\n'outget_plain_content(fpath):

""" return content of zexp-file """= FileToNodes(fpath)parseZobj(objs)compareRevisions(fpath,r1,r2):os,tempfile, fileR1 = tempfile.mkstemp(), fileR2 = tempfile.mkstemp()

#print fileR1,fileR2.system('svn cat \'%s\'@%s > %s' % (fpath,r1,fileR1)).system('svn cat \'%s\'@%s > %s' % (fpath,r2,fileR2)), out1 = tempfile.mkstemp(), out2 = tempfile.mkstemp()

#print out1,out2(out1,'wb').write(get_plain_content(fileR1))(out2,'wb').write(get_plain_content(fileR2)).system('C:\Program Files\KDiff3\kdiff3.exe %s %s' % (out1,out2)).remove(fileR1).remove(fileR2).remove(out1).remove(out2)compare_files(path1,path2):os,tempfile, out1 = tempfile.mkstemp(), out2 = tempfile.mkstemp()(out1,'wb').write(get_plain_content(path1))(out2,'wb').write(get_plain_content(path2)).system('"C:\Program Files\KDiff3\kdiff3.exe" %s %s' % (out1,out2)).remove(out1).remove(out2)__name__=='__main__':syslen(sys.argv)==1:'Usage: %s COMMAND [ARGUMENTS]' % __file__'Available commands:\n\t compare_svn - compare revisions zexp file\n\t compare_file - compare files'.exit(1)=sys.argv[1]command == 'compare_svn':len(sys.argv)!=5:'Usage: %s %s FILEPATH REVISION1 REVISION2' % (__file__, command): compareRevisions(sys.argv[2],sys.argv[3],sys.argv[4])command == 'compare_file':len(sys.argv)!=4:'Usage: %s %s FILEPATH1 FILEPATH2' % (__file__, command): compare_files(sys.argv[2],sys.argv[3])

Похожие работы на - Создание системы мониторинга уровня знаний

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!