Введение
В данном документе проводится полное описание процесса проектирования автоматизированной библиотечной системы оценки, начиная с постановки задачи в виде технического задания и заканчивая описанием программы и методики испытаний.
Расчетно-пояснительная записка включает техническое задание, конструкторскую и технологическую части, а также приложение.
Конструкторская часть включает описание таких аспектов проектирования как предметная область, структурная схема программы, инфологическая и даталогическая модели. В дополнение к этому в данной части проводится обоснование выбора СУБД, операционной системы и средств разработки.
Технологическая часть содержит детальное описание графа диалога, руководство пользователя, а также программу и методику испытаний. В руководстве пользователя приведено подробное описание процесса работы с программой.
В приложении к расчетно-пояснительной записке представлены графические материалы, описание которых приводится на протяжении всей расчетно-пояснительной записки. Также приложение включает исходный текст программного продукта.
Содержание
Техническое задание…………………………………………………………………………...5
1. Наименование проекта………………………………………………………….…..5
2. Основание для разработки……………………………………………………….…5
3. Исполнитель…………………………………………………………………………5
4. Цель и назначение разработки…………………………………………………..….5
5. Содержание работы……………………………………….…………………………5
5.1. Задачи, подлежащие решению……………………………………………5
5.2. Требования к программному изделию…………………………………...6
5.3. Требования к составу программных компонентов..…….………………7
5.4. Требования к архитектуре системы.……….……………………………..7
5.5. Требования к базе данных ………………….…………..…..…………….7
5.6. Требования к входным и выходным данным …………..……………….8
5.7. Требования к составу и характеристикам технических средств……….8
5.8. Требования к лингвистическому обеспечению…...…………………….8
6. Этапы разработки……………………………………………………..……………..8
7. Требования к документации ………..…………...………………….……………..9
8. Порядок приема……….. ……………..………….………………………………...9
9. Дополнительные условия……………..…………………………………………...9
Конструкторская часть………………………………………………………………………10
1. Общетехническое обоснование разработки…………..…………………………..10
1.1. Описание предметной области…………...….………………………….10
1.2. Функциональные задачи приложения………………………………….10
1.3. Анализ аналогов и прототипов……….......…………………………….10
2. Разработка структуры программного изделия………...………………………….12
2.1. Выявление потребителей и источников информации……..…………12
2.2. Сравнительный анализ средств разработки системы…….….…..……13
2.3. Выбор системы разработки……………………………….….…..……..14
2.4. Проектирование базы данных………………………….….…..………..14
2.5. Описание инфологической модели предметной области..….………...14
2.6. Даталогическая модель…………………………………..….…………..17
Технологическая часть……………………………………………………………………….19
1. Разработка интерфейсов взаимодействия пользователя с системой…….……...19
1.1. Разработка экранных форм (страниц)……………….….………………19
1.2. Разработка графа диалога……………………………..…………………23
2. Руководство пользователя………………………………………….....…….……...24
2.1. Открытие приложения……………...……………………………………24
2.2. Постраничная навигация…………….…………………………………..24
2.3. Отправка извещений о задолженностях перед библиотеками.………..27
2.4. Предоставление пользователям полномочий сотрудников библиотек.27
3. Программа и методика испытаний…………………………………..…….……...27
3.1. Объект испытаний……….……………………….………………………27
3.2. Цель испытания……………………..……………………………………27
3.3. Состав предъявляемой документации ……..……….…………………..28
3.4. Технические требования……………………………………..…………..28
3.5. Порядок проведения испытаний……..………………………………….28
Заключение…………………………...………….…………………………………………….37
Список используемой литературы……………….…………………………………………38
Приложение……………………………….……….…………………………………………..39
1. Листинг основных модулей программы…...…..………………………………..39
1.1. Описание моделей для работы с базой данных……………………….39
1.2. Разметка веб-страниц…….……………………………………………..44
1.3. Дизайн веб-страниц…….……………………………………………….45
1.4. Функциональные модули……….………………………………………62
2. Графическое приложение…………………...…..………………………………..97
Техническое задание
1. Наименование проекта
Автоматизированная информационная библиотечная система (АИС “Библиотеки”).
2. Основание для разработки
Основанием для разработки является задание на курсовой проект, утвержденное кафедрой «Автоматизированные системы обработки информации и управления» МГТУ им. Н.Э. Баумана.
3. Исполнитель
Исполнителем является студент МГТУ им. Н.Э.Баумана группы ИУ 5-81 Николаев Константин Александрович.
4. Назначение и цель разработки
Разрабатываемая автоматизированная информационная система предназначена для хранения информации о библиотеках и их книжных фондах. Система должна позволять пользователю быстро и легко осуществлять поиск информации о книгах, а также совершать заказы книг в различных библиотеках. Также система должна информировать пользователя о задолженностях перед библиотеками.
5. Содержание работы
5.1. Задачи, подлежащие решению
5.1.1 Анализ предметной области и создание ее формального описания
5.1.2 Определение функций, выполняемых системой;
5.1.3 Разработка инфологической и даталогической моделей системы;
5.1.4 Выбор основной технологии и средств разработки и реализации программных модулей;
5.1.5 Создание базы данных;
5.1.6 Составление структурной схемы системы;
5.1.7 Разработка интерфейса взаимодействия программы с пользователем;
5.1.8 Разработка алгоритма работы программы;
5.1.9 Разработка графа диалога и набора страниц;
5.1.10 Оформление документации.
5.2 Требования к программному изделию
5.2.1 Требования к функциональным характеристикам:
Автоматизированная библиотечная система должна выполнять следующие функции:
5.2.1.1 Содержать макет сайта, с помощью которого пользователь сможет использовать ресурсы библиотек.
5.2.1.2 Содержать постраничную навигацию по сайту системы.
5.2.1.3 Реализовывать возможность добавления новых библиотек и книг в систему.
5.2.1.4 Реализовывать считывание, первичный анализ корректности и сохранение в базу данных введённой пользователем информации.
5.2.1.5 Осуществлять поиск библиотек, книг по введенному пользователем запросу.
5.2.1.6 Реализовывать функцию онлайн-заказа книг c отправкой пользователю талона, подтверждающего факт заказа, по электронной почте.
5.2.1.7 Осуществлять отправку письма по указанному пользователем E-mail адресу для уведомления пользователя о задолженностях перед библиотеками.
5.2.1.8 Содержать список пользователей, получивших книг на руки с указанием дат получения, и список должников библиотек.
5.2.1.9 Основное управление и настройка системы должны осуществляться путём изменения данных в базе.
5.2.2 Требования к интерфейсу пользователя:
Пользователь должен иметь возможность:
5.2.2.1. Зайти на веб-сайт системы.
5.2.2.2. Чётко понимать, каким образом необходимо вести заполнение форм для добавления новых данных, и, в случае пропуска полей, получать сообщение о необходимости их заполнения.
5.2.2.3. Отправлять запросы для получения информации о книгах и библиотеках и оперативно получать результаты этих запросов.
5.2.2.4. Получать на E-mail письмо с информацией о задолженностях перед библиотеками.
5.3 Требования к составу программных компонентов
Для функционирования данной системы необходимо, чтобы на компьютере были установлены следующие программные продукты:
• ОС Microsoft Windows XP или старше;
• MS SQL Server 2005 Express Edition или более высокой редакции;
5.4 Требования к архитектуре системы
Система должна включать в себя:
• Веб-сайт, производящую работу с базой данных и реализующую интерфейс с пользователем;
• базу данных для хранения информации о библиотеках, книгах, пользователях и заказов.
• приложение, ответственное за выполнение функций системы и рассылку
E-mail сообщений с информацией о задолженностях.
5.5 Требования к базе данных
Автоматизированная система использует СУБД SQL Server 2005 для хранения следующей информации:
• список библиотек, использующих систему
• список книг
• список пользователей
• количество и местонахождение книг в конкретной библиотеки
• статистика о библиотеках, книгах и пользователях
5.6 Требования к входным и выходным данным
5.6.1 Входные данные
Входными данными является информация о книгах или библиотеках, полученная от администратора, или запросы от пользователя.
5.6.2 Выходные данные
Выходными данным является информация о библиотеках и книгах, найденная по запросу пользователю, и информация о заказах или
о задолженностях перед библиотеками, направляемая в письме пользователю.
5.7 Требования к составу и характеристикам технических средств
Приложение должно функционировать на IBM-совместимой ЭВМ следующей конфигурации:
• процессор семейства Intel Pentium IV и выше;
• оперативная память не менее 1 Гбайт;
• дисковая подсистема со свободным дисковым пространством
не менее 2 Гбайт;
• цветной монитор с поддержкой SVGA–режимов;
• стандартная русифицированная клавиатура;
• манипулятор мышь.
5.8 Требования к лингвистическому обеспечению
Интерфейс пользователя должен быть реализован на русском языке.
6. Этапы разработки
№ Этапы разработки Срок начала Срок выполнения
1 Разработка технического задания 07.02.2014 12.02.2014
2 Разработка эскизного проекта 14.02.2014 26.02.2014
3 Разработка технического проекта 28.02.2014 12.03.2014
4 Разработка программы 14.03.2014 02.04.2014
5 Отладка программы 04.04.2014 16.04.2014
6 Разработка программной документации 18.04.2014 07.05.2014
7 Оформление и представление документации 09.05.2014 14.05.2014
8 Защита выпускной работы До 02.07.2014
7. Требования к документации
Для приема программного изделия должны быть предоставлены следующие документы:
7.2. Техническое задание;
7.3. Расчетно-пояснительная записка;
7.4. Руководство пользователя;
7.5. Программа и методика испытаний;
7.6. Копия листов графической части.
8. Порядок приема
Прием и контроль программного изделия осуществляется в соответствии с документом «Программа и методика испытаний».
9. Дополнительные условия
Данное техническое задание может уточняться и изменяться в установленном порядке.
Конструкторская часть
1. Общетехническое обоснование разработки.
1.1. Описание предметной области
Предметной областью данной системы являются библиотеки. Система хранит данные о библиотеках, их каталогах и книгах. Пользователь может искать нужные им книги и осуществлять их заказ.
Данный программный продукт может быть использован в любой библиотеке. Система реализована в виде веб-приложения, поэтому она может быть размещена в Интернете и открыта для свободного доступа для одновременного использования многими библиотеками.
Дальнейшая разработка модели предметной области описана в разделе «Проектирование базы данных».
1.2. Функциональные задачи приложения
Доступ к базе данных, содержащей следующую информацию:
• О библиотеках
• О книгах
• О книгах в библиотеках
• О заказах
Управление профилями пользователей.
Реализация рассылки извещений о невозвращенных в срок книгах:
• Проверка возвращения книг в срок каждым пользователь
• Рассылка извещений
Обработка данных и вывод информации для администратора базы данных.
• Управление правами доступа пользователей
• Просмотр данных, оставленных пользователями сайта
(Все данные указанные действия администратор обязан совершать через СУБД)
1.3. Анализ аналогов и прототипов
В качестве прототипа разрабатываемого продукта рассмотрим аналог системы:
http://library.bmstu.ru/ - сайт библиотеки МГТУ им. Баумана. Данный сайт оснащен эффективным и быстрым механизмом поиска, что является его главным достоинством. Сайт имеет достаточно дружелюбный интерфейс. Пользователь может узнавать информацию о своих книгах через личный кабинет. Недостатком является отсутствие возможности регистрации напрямую через сайт.
Проанализировав этот пример можно сделать выводы, что в разрабатываемом приложении стоит выделить следующие критерии:
• Поиск информации должен эффективным, т.е. по запросу пользователя должно выдаваться как можно больше релевантных результатов.
• Система должна иметь высокую скорость загрузки и обработки информации для оперативной работы.
• Система должна иметь средства для поддержания обратной связи с пользователем: информирования пользователя о его заказах, задолженностях и т.п.
Параметры сравнения Варианты сравнения
АИС «Библиотеки» Библиотека
МГТУ им. Баумана
1. Простота организации интерфейса Оч.хор. Хор.
2. Эффективность поиска Хор. Отл.
3. Оперативность работы системы Отл. Отл.
4. Поддержка обратной связи
с пользователем Отл. Хор.
Таблица 1. Сравнительный анализ аналогов с разрабатываемой системой.
Перевод качественных характеристик в количественные производится в соответствии со следующей таблицей:
Качественный показатель Отл. Оч.хор. Хор. Удовл. Посредств. Плохо Оч. плохо Неуд.
Количественный показатель (нормированная шкала) 1 0,9 0,8 0,6 0,5 0,4 0,2 0
Проведение нормализации и определение весовых коэффициентов приводит к следующим результатам:
Параметры сравнения α Варианты сравнения
АИС «Библиотеки» Библиотека
МГТУ им. Баумана
1. Простота организации интерфейса 0.1 0,9 0,8
2. Эффективность поиска 0.4 0,8 1
3. Оперативность работы системы 0.3 1 1
4. Поддержка обратной связи
с пользователем 0.2 1 0,8
ИТОГО: 1 0,91 0,94
Таблица 2. Итоговые результаты сравнительного анализа аналогов системы.
Проведенный анализ показывает, что разрабатываемая система несколько уступает аналогу, однако в ней были учтены его недостатки, поэтому программный продукт АИС “Библиотеки” может быть использован как основа для более продвинутого варианта библиотечной системы.
2. Разработка структуры программного изделия
2.1. Выявление потребителей и источников информации.
В ходе анализа предметной области были выявлены информационные потребности пользователей, источники и потребители информации.
Потребителями информации являются потенциальные клиенты библиотек.
Источником информации являются данные вводимые сотрудниками библиотек в систему.
2.2. Сравнительный анализ средств разработки системы.
Были рассмотрены три варианта средств разработки системы. Сравнительный анализ вариантов приведен в таблице 3.
MS Visual Studio + MS SQL Server PHP + PostgreSQL Delphi +
MS Access
Опыт работы 1 год 4 месяца 1,5 год
Распространенность отличная хорошая удовл.
Подддержка фирм-производителей отличная удовл. отличная
Совместимость компонентов отличная хорошая хорошая
Набор функциональных возможностей отличный хороший удовл.
Таблица 3. Сравнительный анализ средств разработки системы.
Для определения оптимального варианта с учетом указанных факторов воспользуемся методом взвешенной суммы.
Вначале рассчитываем коэффициент α для каждого фактора, указывающий важность данного фактора. Далее рассчитываем коэффициенты соответствия рассматриваемых вариантов средств разработки эталонному значению. Далее по формуле Y=ΣKij•α рассчитаем итоговый весовой коэффициент каждого варианта. Вариант с наибольшим итоговым весовым коэффициентом, согласно этому методу, будет оптимальным.
Окончательные результаты сравнительного анализа и выбор средств разработки системы приведены в таблице 4.
α
MS Visual Studio + MS SQL Server PHP + PostgreSQL Delphi +
MS Access
Опыт работы 0.2 0.6 0.2 1
Распространенность 0.1 1 0.8 0.6
Подддержка фирм-производителей 0.1 1 0.6 1
Совместимость компонентов 0.3 1 0.8 0.8
Набор функциональных возможностей 0.3 1 0.8 0.6
Σ 0.82 0.68 0.78
Таблица 4.Результаты сравнительного анализа и выбор средств разработки системы
По результатам анализы был выбран вариант: MS Visual Studio + MS SQL Server.
2.3. Выбор среды разработки.
Выбор архитектуры системы предопределен её локальным использованием на базе операционной системы Windows и выбранными средствами разработки.
В качестве системы разработки и исполняемого модуля выбрана среда программирования Microsoft Visual Studio 2012. Данная среда разработки имеет следующие положительные характеристики:
1. Поддерживает програмную платформу .NET Framework, позволяющую выполнять программы, написанные на разных языках программирования, что обеспечивает гибкость при разработке (в качестве языка программирования был выбран объектно-ориентированный язык C#).
2. Включает локальный сервер ASP.NET Development Server для проверки работоспособности web-приложения без установки постороннего ПО.
3. Удобный интерфейс, поддержка фирмы-производителя (Microsoft) и широкий ассортимент обучающих статей и примеров по разработки программного обеспечения.
4. Предоставление бесплатной лицензии на использование Microsoft Visual Studio 2012 для студентов технических вузов в рамках программы “Dreamspark” от компании Microsoft.
Для разработки дизайна и верстки страниц были выбраны технологии HTML и CSS. Данные технологии являются наиболее распространенными при разработке верстки и дизайна интернет страниц, а также были рассмотрены в рамках учебного курса.
Пользовательский интерфейс разработан с использованием технологии ASP.NET. Данная технология предоставляет большой набор средств для быстрого создания динамических элементов и элементов управления.
2.4. Проектирование базы данных.
В качестве СУБД была выбрана Microsoft SQL Server 2012, т.к. она в полной мере отвечает требованиям разрабатываемого продукта. Выбранная СУБД хорошо совместима со средой разрабротки и поддерживает язык запросов Transact-SQL.
2.5. Описание инфологической модели предметной области.
В результате анализа предметной области были выделены сущности, атрибуты, взаимосвязь между ними и построена инфологическая модель базы данных. Схема инфологической модели представлена на листе 2.
2.5.1. Описание сущностей и их атрибутов
2.5.1.1. Сущность «Библиотека»
Атрибуты:
• БиблиотекаId – Первичный ключ
• Название
• Адрес
• Телефон
• Число уникальных наименований
2.5.1.2. Сущность «Книга»
Атрибуты:
• КнигаId – Первичный ключ
• Название
• Автор
• Издательство
• Год издания
• Тематика
• ISBN
• Данные изображения
• Mime-тип изображения
2.5.1.3. Сущность «Книга В Библиотеке»
Атрибуты:
• Книга В БиблиотекеId – Первичный ключ
• Общее количество
• Текущее количество
• Отдел
• Шкаф
• Полка
•
2.5.1.4. Сущность «Заказ»
Атрибуты:
• Заказ ID – Первичный ключ
• Дата заказа
• Дата выдачи
• Дата возврата
• Вернуть не позднее
• Возвращена
• ПользовательId
• Фамилия пользователя
• Имя пользователя
2.5.1.5. Сущность «Пользователь»
Атрибуты:
• ПользовательId – Первичный ключ
• Логин
• Фамилия
• Имя
• Дата рождения
• E-mail
2.5.2. Описание связей
2.5.2.1. Связь «Содержится в»
Объединяет сущности «КнигаВБиблиотеке» и «Библиотека».
Тип связи – М:1
2.5.2.2. Связь «Хранится в»
Объединяет сущности «Книга» и «КнигаВБиблиотеке».
Тип связи – 1:М
2.5.2.3. Связь «На»
Объединяет сущности «Заказ» и «Книга».
Тип связи – М:1
2.5.2.4. Связь «Кому»
Объединяет сущности «Заказ» и «Библиотека».
Тип связи – М:1
2.5.2.5. Связь «От кого»
Объединяет сущности «Заказ» и «Пользователь».
Тип связи – М:1
2.5.2.6. Связь «Работает в»
Объединяет сущности «Пользователь» и «Библиотека».
Тип связи – М:М
2.6. Даталогическая модель.
На основе инфологической модели, описанной в пункте 2.2.5 данного документа, была построена даталогическая модель для реляционной СУБД Microsoft SQL Server 2005 Management Studio.
Для обеспечения целостности данных в соответствующие сущности инфологической модели добавляются ключевые атрибуты, которые функционально определены и зависят только от первичного ключа.
При отображении инфологической модели в даталогическую, сущности становятся таблицами, атрибуты – полями таблиц. В даталогическую модель вводятся связи, аналогичные связям инфологической модели.
Структура даталогической модели представлена на листе 1 в графической части раздела «Приложение» данной пояснительной записки.
Library
PK LibraryId Int
Name Nvarchar(max)
Adress Nvarchar(max)
Phone Nvarchar(max)
TotalUniqueBooks Int
Book
PK BookId Int
Name Nvarchar(max)
Author Nvarchar(max)
PublishingHouse Nvarchar(max)
YearOfPublishing Int
Subject Nvarchar(max)
ISBN Nvarchar(max)
ImageData Varbinary(max)
ImageMimeType Nvarchar(max)
Order
PK OrderId Int
DateOfOrder Datetime
DateOfIssue Datetime
DateOfReturn Datetime
ReturnBefore Datetime
Returned Bit
BookId Int
LibraryId Int
UserId Int
UserLastName Nvarchar(max)
UserFirstName Nvarchar(max)
User
PK UserId Int
Login Nvarchar(max)
LastName Nvarchar(max)
FirstName Nvarchar(max)
Birthdate Datetime
Email Nvarchar(max)
UserInLibrary
PK UserInLibraryId Int
UserId Int
LibraryId Int
Технологическая часть
1. Разработка интерфейсов взаимодействия пользователя с системой
1.1. Разработка экранных форм (страниц).
Главная (родительская) страница (home/index)
Все страницы разрабатываемого сайта библиотечной системы имеют общий шаблон стиля, а также наследуют свой формат от родительской страницы и включают все блоки, описанные ниже. Главная страница разделена на следующие блоки:
• Заголовок – Содержит название системы, а также функциональные кнопки «Вход», «Выход», «Регистрация». Также отображается имя пользователя.
• Меню – Содержит ссылки на разделы: «Главная страница», «Библиотеки», «Книги», «Контакты».
Рисунок 1. Главная страница.
Страница со списком книг (book/index)
Как и другие страницы сайта библиотечной системы имеет общий шаблон стиля, а также наследуют свой формат от родительской страницы и включают все блоки описанные ниже.
• Список библиотек
• Строка поиска
• Фильтр для выбора критерия поиска
Рисунок 2. Страница со списком книг.
Страница с формой добавления книги (book/create)
Рисунок 3. Страница с формой добавления книги.
Страница с подробным описанием книги (book/details/1)
Рисунок 4. Страница с подробным описанием книги.
Страница с формой редактирования книги (book/edit/1)
Рисунок 5. Страница с формой редактирования книги.
Получение письма с талоном заказа.
• При заказе книге, на почту пользователю отправляется письмо с талоном, необходимым для получения заказа в библиотеке
Рисунок 6. Получение письма с талоном через веб-портал почтового провайдера rambler.ru.
Рисунок 7. Образец талона заказа.
Получение письма с извещением о задолженности.
• Раз в сутки система проводит проверку на наличие у пользователей задолженностей перед библиотеками и отправляет им по электронной почте соответствующие извещения.
Рисунок 8. Получение письма с извещением через веб-портал почтового провайдера rambler.ru.
1.2. Разработка графа диалога
Для взаимодействия пользователя с системой разработан граф диалога, представленный на листе 4.
2. Руководство пользователя
2.1. Открытие приложения
Открытие приложения осуществляется после ввода в адресную строку имени домена, на котором будет зарегистрировано данное web-приложение.
При открытии в браузере отображается главная страница приложения Home/Index. На сайте Библиотечной системы пользователь может перейти на следующие страницам:
1. «Главная страница»
2. «Контакты»
3. «Регистрация»
4. «Вход»
Если пользователь авторизирован, также будут доступны следующие страницы:
5. «Библиотеки»
6. «Книги»
7. Личный кабинет (ссылка с логином (именем входа) пользователя)
2.2. Постраничная навигация
2.2.1. «Главная страница»
На главной странице содержится краткая информация о системе, и о том, как воспользоваться ее услугами простым пользователям и сотрудникам библиотек.
2.2.2. «Контакты»
На странице «Контакты» содержится контактная информация для обратной связи пользователя с сотрудниками библиотечной системы.
2.2.3. «Библиотеки»
• На странице «Библиотеки» содержится список библиотек, использующих данную систему, со ссылками на подробное описание; строка поиска и выпадающий список для выбора критерия поиска.
• Для администратора также доступна ссылка для добавления новых библиотек в систему.
2.2.3.1. «Подробно»
На странице находится подробное описание библиотеки и ссылки для редактирования (для сотрудников или администратора) и удаления (только для администратора) библиотек из системы. Здесь же находятся ссылки на «Список книг в библиотеке», «Список заказов в библиотеке», «Список пользователей, получивших книги» и «Список должников» (для сотрудников и администратора).
2.2.3.2. «Редактировать»
На странице находится форма для редактирования данных о библиотеке.
2.2.4. «Книги»
• На странице «Книги» содержится список Книги, информация о которых содержится в системе, со ссылками на подробное описание; строка поиска и выпадающий список для выбора критерия поиска.
• Для администратора и сотрудников библиотек также доступна ссылка для добавления новых библиотек в систему.
2.2.4.1. «Подробно»
На странице находится подробное описание книги и ссылки для редактирования (для сотрудников или администратора) и удаления (только для администратора) книг из системы. Здесь же находятся ссылка на «Список библиотек, в которых имеется эта книга»
2.2.4.2. «Редактировать»
На странице находится форма для редактирования данных о книге.
2.2.5. «Список книг в библиотеке»
• На странице «Список книг в библиотеке» содержится список книг, имеющихся в выбранной библиотеке, со ссылками на подробное описание и ссылка на форму заказа книги. Если в настоящий момент в наличии нет ни одного экземпляра книги, пользователь получит соответствующее уведомление.
2.2.5.1. «Подробно»
На странице находится подробное описание местонахождения книги, ссылка на подробное описание самой книги и ссылки для редактирования и удаления (последние две доступны только для сотрудников или администратора) книг из системы. Здесь же находятся ссылка на «Список библиотек, в которых имеется эта книга»
2.2.6. «Список библиотек, в которых имеется эта книга»
• На странице «Список библиотек, в которых имеется эта книга» содержится список библиотек, в которых имеется выбранная книга, со ссылками на подробное описание и ссылка на форму заказа книги. Если в настоящий момент в наличии нет ни одного экземпляра книги, пользователь получит соответствующее уведомление.
2.2.6.1. «Подробно»
На странице находится подробное описание местонахождения книги, ссылка на подробное описание самой книги и ссылки для редактирования и удаления (последние две доступны только для сотрудников или администратора) книг из системы. Здесь же находятся ссылка на «Список библиотек, в которых имеется эта книга»
2.2.7. «Список заказов в библиотеке»
• На странице «Список заказов в библиотеке» содержится список заказов конкретной библиотеки со ссылками на подробное описание заказа, библиотеки и книги.
2.2.8. «Список пользователей, получивших книги»
• На странице «Список пользователей, получивших книги» содержится список пользователей, получивших книги на руки в конкретной библиотеке.
2.2.9. «Список должников»
• На странице «Список должников» содержится список пользователей, имеющих задолженности перед конкретной библиотекой.
2.2.10. Подробное описание заказа.
На странице находится подробное описание заказа и ссылки для редактирования (для сотрудников или администратора) и удаления (для пользователя, сделавшего заказ, или администратора) заказов из системы. Здесь же находятся ссылки на «Список заказов в библиотеке» и «Список заказов пользователя».
2.2.11. «Регистрация»
С помощью формы регистрации пользователь может зарегистрироваться в системе.
2.2.12. «Вход»
С помощью формы входа осуществляется аутентификация пользователя в системе.
2.2.13. Личный кабинет
• В личном кабинете пользователь может просмотреть список своих заказов.
• В личном кабинете находятся формы для редактирования личных данных и смены пароля.
2.2.14. Список заказов пользователя
• На странице «Список заказов пользователя» содержится список заказов конкретного пользователя со ссылками на подробное описание заказа, библиотеки и книги.
2.3. Отправка извещений о задолженностях перед библиотеками.
• Раз в сутки система проводит проверку на наличие у пользователей задолженностей перед библиотеками и отправляет им по электронной почте соответствующие извещения.
2.4. Предоставление пользователям полномочий сотрудников библиотек.
Для предоставления пользователю прав сотрудника библиотеки необходимо выполнить следующие действия:
• Присвоить пользователю роль “Librarian” через таблицу «webpages_UsersInRole» в базе данных «KP_Users»
• Добавить связь между пользователем и библиотеку через таблицу «UserInLibrary»
Эти действия необходимо выполнить через СУБД.
3. Программа и методика испытаний
3.1. Объект испытаний
Автоматизированная библиотечная система (АИС “Библиотеки”).
3.2. Цель испытаний
Целью испытаний является проверка реализации всех функций и требований, указанных в техническом задании.
3.3. Состав предъявляемой документации
При проведении испытаний предоставляются следующие документы:
1. Техническое задание;
2. Руководство пользователя;
3. Программа и методика испытаний;
3.4. Технические требования
3.4.1. Задачи, подлежащие решению
Для корректного проведения испытаний следует изучить пункт «Руководство пользователя» расчетно-пояснительной записки и соблюдать все требования и инструкции, изложенные в этом пункте.
3.4.2. Требования к программной документации
Должны быть представлены все документы, указанные в пункте «Состав предъявляемой документации» данного документа.
3.5. Порядок проведения испытаний
3.5.1. Состав и структура технических и программных средств
Программный продукт разработан для использования под управлением операционной системы Microsoft Windows XP (или более поздних версий). Система разработана в Microsoft Visual Studio на языке C#, следовательно, для просмотра исходных кодов необходимо наличие данной среды разработки. База данных разработана на MS SQL Server 2012. Необходимые технические характеристики ПК объявлены в пункте «Требования к техническому обеспечению» технического задания.
3.5.2. Последовательность испытаний
3.5.2.1. Испытание системы должно проводиться в следующей последовательности:
• Установка и настройка системы на персональном компьютере или сервере
• Запуск системы
• Проведение испытаний
• Завершение работы
3.5.2.2. Последовательность проведения испытаний:
№ пункта ТЗ № п.п. Выполняемые действия Ожидаемый результат
5.2.1.1 1 Открытие страницы home/index
Вход на главную страницу сайта, с которой начинается работа с системой. (Рисунок 1)
5.2.1.2 2 Нажатие кнопок с именами страниц. Переход по страницам, содержащим различную информацию. (Рисунок 2,3,4)
5.2.1.3 3 Выбор пунктов «Добавить» на страницах «Библиотеки» и «Книги». Заполнение соответствующих форм. Добавление в базу данных записей с информацией о библиотеке и книге. (Рисунок 5,6)
5.2.1.4 4 Попытка добавить запись с некорректно заполненными полями. Появление сообщения об ошибке в соответствующем поле. Данные не будут сохранены. (Рисунок 7)
5.2.1.5 5 Введение запроса в строку поиска, выбор критерия поиска, нажатие кнопки «Поиск» на страницах «Библиотеки», «Книги». Вывод списка результатов запроса. (Рисунок 8,9)
5.2.1.6 6 Выбор пункта заказать на странице «Список книг в библиотеке» или на странице «Список библиотек, в которых имеется эта книга». Нажатие кнопки «Добавить».
Добавление в базу данных записи с информацией о заказе. Получение пользователем письма с талоном заказа. (Рисунок 10,11,12)
5.2.1.7 7 Проверка системой необходимости отправки извещения. Получение пользователем извещения о задолженности. (Рисунок 13)
5.2.1.8
8 Выбор пунктов
«Список пользователей, получивших книги» и «Список должников» на странице любой библиотеки. Загрузка страниц со списком пользователей, получивших книги на руки, и списком должников. (Рисунок 14, 15)
5.2.1.9
9 Добавление записей в таблицы «UserInLibary», «webpages_UsersInRole» через СУБД. Появление у пользователя полномочий для редактирования данных о библиотеке, добавления книг в базу данных и в библиотеку, просмотра списка заказов и списка должников библиотеки. (Рисунок 16)
3.6. Приложение. Изображения результатов испытаний
Рисунок 1. «Главная страница»
Рисунок 2. «Библиотеки»
Рисунок 3. «Книги»
Рисунок 4. «Контакты»
Рисунок 5. Добавление новой библиотеки
Рисунок 6. Добавление новой книги
Рисунок 7. Сообщение об ошибке при некорректном заполнении полей
Рисунок 8. Поиск библиотек
Рисунок 9. Поиск книг
Рисунок 10. Выбор книги для заказа
Рисунок 11. Добавление заказа
Рисунок 12. Получение пользователем талона заказа
Рисунок 13. Получение пользователем извещения о задолженности
Рисунок 14. «Список пользователей, получивших книги»
Рисунок 15. «Список должников»
Рисунок 16. Просмотр страницы библиотеки с правам сотрудника
Заключение
В процессе разработки проекта был изучен такие важные элементы современных библиотек, как поиск книг в фондах библиотек и поддержание связи с читателями. В частности, было рассмотрено использование автоматизированной системы для реализации этого процесса.
На основе детального анализа предметной области составлена укрупненная схема работы библиотечной системы и определены основные задачи, которые должна решать данная автоматизированная информационная система.
Проведен сравнительный анализ аналогов и прототипов. Показаны отличия разработанной системы по сравнению с существующими по ряду параметров:
• Простота организации интерфейса
• Эффективность поиска
• Оперативность работы системы
• Поддержка обратной связи с пользователем
Разработаны и приведены на плакатах инфологическая и даталогическая модели базы данных, а также граф диалога пользователя с системой. Разработан сайт системы, через который происходит общение пользователя с системой. Визуальное описание процесса общения приведено в расчетно-пояснительной записке и на плакате.
Список используемой литературы
1. В.И. Кузовлев, Ю.Н.Филиппович. Методические указания по выполнению выпускной работы бакалавра по специальности "Информатика и вычислительная техника"
для студентов кафедры ”Системы обработки информации и управления",
М.: МГТУ им Н.Э. Баумана, 2005 г.
2. Фримен А., Сандерсон С. ASP.NET MVC 3 Framework с примерами на C# для
профессионалов, 3-е изд.: Пер. с англ. – М. : ООО “И.Д. Вильямс”, 2012. – 672 с. :
ил. – Парал. тит. англ. ISBN 978-5-8459-1758-4 (рус.).
3. Интернет источники:
http://msdn.microsoft.com
http://stackoverflow.com
http://htmlbook.ru
Приложение
1. Листинг основных модулей программы
1.1. Описание моделей для работы с базой данных
Модели для доступа к базе KP_Library описаны в файле LibraryModels.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Web.Mvc;
namespace KP_Library.Models
{
public class LibraryContext: DbContext
{
public LibraryContext()
: base("LibraryContext")
{
}
public DbSet<Library> Libraries { get; set; }
public DbSet<Book> Books { get; set; }
public DbSet<BookInLibrary> BooksInLibrary { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<UserInLibrary> UsersInLibrary { get; set; }
}
[Table("Library")]
public class Library
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int LibraryId { get; set; }
[Required(ErrorMessage= "Требуется поле Название")]
[DisplayName("Название")]
public string Name { get; set; }
[Required(ErrorMessage = "Требуется поле Адрес")]
[DisplayName("Адрес")]
public string Adress { get; set; }
[Required(ErrorMessage = "Требуется поле Номер телефона")]
[DisplayName("Номер телефона")]
[RegularExpression(@"^((8|+7)[- ]?)?((?d{3})?[- ]?)?[d- ]{7,10}$")]
public string Phone { get; set; }
[Required]
[HiddenInput]
[DisplayName("Число уникальных наименований")]
public int TotalUniqueBooks { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual ICollection<BookInLibrary> BooksInLibrary { get; set; }
public virtual ICollection<UserInLibrary> UsersInLibrary { get; set; }
}
[Table("Book")]
public class Book
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int BookId { get; set; }
[Required(ErrorMessage = "Требуется поле Название")]
[DisplayName("Название")]
public string Name { get; set; }
[Required(ErrorMessage = "Требуется поле Автор")]
[DisplayName("Автор")]
public string Author { get; set; }
[Required(ErrorMessage = "Требуется поле Издетельство")]
[DisplayName("Издательство")]
public string PublishingHouse { get; set; }
[Required(ErrorMessage = "Требуется поле Год издания")]
[DisplayName("Год издания")]
public int YearOfPublishing { get; set; }
[Required(ErrorMessage = "Требуется поле Тематика")]
[DisplayName("Тематика")]
public string Subject { get; set; }
[Required(ErrorMessage = "Требуется поле ISBN")]
[RegularExpression(@"(?=.{17}$)97(?:8|9)([ -])d{1,5}1d{1,7}1d{1,6}1d$", ErrorMessage="Номер ISBN должен соответствовать стандарту ISBN-13")]
public string ISBN { get; set; }
public byte[] ImageData { get; set; }
[HiddenInput(DisplayValue = false)]
public string ImageMimeType { get; set; }
public virtual ICollection<BookInLibrary> BooksInLibrary { get; set; }
public virtual ICollection<Order> Orders { get; set; }
}
[Table("BookInLibrary")]
public class BookInLibrary
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int BookInLibraryId { get; set; }
[Required]
[DisplayName("Книга")]
public int BookId { get; set; }
public virtual Book Book { get; set; }
[Required(ErrorMessage = "Требуется поле Всего экземпляров")]
[DisplayName("Всего экземпляров")]
public int TotalQuantity { get; set; }
[Required(ErrorMessage = "Требуется поле Экземпляров в наличии")]
[DisplayName("Экземпляров в наличии")]
public int CurrentQuantity { get; set; }
[Required]
[DisplayName("Библиотека")]
public int LibraryId { get; set; }
public virtual Library Library { get; set; }
[Required(ErrorMessage = "Требуется поле Отдел")]
[DisplayName("Отдел")]
public int Department { get; set; }
[Required(ErrorMessage = "Требуется поле Шкаф")]
[DisplayName("Шкаф")]
public int Bookcase { get; set; }
[Required(ErrorMessage = "Требуется поле Полка")]
[DisplayName("Полка")]
public int Shelf { get; set; }
}
[Table("Order")]
public class Order
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int OrderId { get; set; }
[Required(ErrorMessage = "Требуется поле Дата заказа")]
[DisplayName("Дата заказа")]
[DataType(DataType.Date)]
public DateTime? DateOfOrder { get; set; }
[DisplayName("Дата выдачи")]
[DataType(DataType.Date)]
public DateTime? DateOfIssue { get; set; }
[DisplayName("Дата возврата")]
[DataType(DataType.Date)]
public DateTime? DateOfReturn { get; set; }
[DisplayName("Вернуть не позднее")]
[DataType(DataType.Date)]
public DateTime? ReturnBefore { get; set; }
[Required]
[DisplayName("Книга возвращена")]
public bool Returned { get; set; }
[Required]
[DisplayName("Книга")]
public int BookId { get; set; }
public virtual Book Book { get; set; }
[Required]
[DisplayName("Библиотека")]
public int LibraryId { get; set; }
public virtual Library Library { get; set; }
[Required]
[DisplayName("Пользователь")]
public int UserId { get; set; }
[DisplayName("Фамилия пользователя")]
public string UserLastName { get; set; }
[DisplayName("Имя пользователя")]
public string UserFirstName { get; set; }
}
[Table("UserInLibrary")]
public class UserInLibrary
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserInLibraryId { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public int LibraryID { get; set; }
public virtual Library Library { get; set; }
}
}
Модели для доступа к базе KP_Users описаны в файле AccountModels.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Globalization;
using System.Web.Security;
namespace KP_Library.Models
{
public class UsersContext : DbContext
{
public UsersContext()
: base("UsersContext")
{
}
public DbSet<User> Users { get; set; }
}
public class RegisterExternalLoginModel
{
[Required]
[Display(Name = "Логин")]
public string Login { get; set; }
public string ExternalLoginData { get; set; }
}
public class LocalPasswordModel
{
[Required(ErrorMessage = "Требуется поле Текущий пароль")]
[DataType(DataType.Password)]
[Display(Name = "Текущий пароль")]
public string OldPassword { get; set; }
[Required(ErrorMessage = "Требуется поле Новый пароль")]
[StringLength(100, ErrorMessage = "{0} должен быть хотя бы {2} символов в длину.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Новый пароль")]
public string NewPassword { get; set; }
[Required(ErrorMessage = "Требуется поле Подтвердите новый пароль")]
[DataType(DataType.Password)]
[Display(Name = "Подтвердите новый пароль")]
[Compare("NewPassword", ErrorMessage = "Новый пароль и подтверждение пароля не совпадают.")]
public string ConfirmPassword { get; set; }
}
public class LoginModel
{
[Required(ErrorMessage = "Требуется поле Логин")]
[Display(Name = "Логин")]
public string Login { get; set; }
[Required(ErrorMessage = "Требуется поле Пароль")]
[DataType(DataType.Password)]
[Display(Name = "Пароль")]
public string Password { get; set; }
[Display(Name = "Запомнить?")]
public bool RememberMe { get; set; }
}
public class RegisterModel
{
[Required(ErrorMessage = "Требуется поле Логин")]
[Display(Name = "Логин")]
public string Login { get; set; }
[Required(ErrorMessage = "Требуется поле Пароль")]
[StringLength(30, ErrorMessage = "Пароль не может быть меньше 6 и больше 30 символов.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Пароль")]
public string Password { get; set; }
[Required(ErrorMessage = "Требуется поле Подтвердите пароль")]
[DataType(DataType.Password)]
[Display(Name = "Подтвердите пароль")]
[Compare("Password", ErrorMessage = "Пароли не совпадают.")]
public string ConfirmPassword { get; set; }
[Required(ErrorMessage = "Требуется поле Фамилия")]
[Display(Name = "Фамилия")]
public string LastName { get; set; }
[Required(ErrorMessage = "Требуется поле Имя")]
[Display(Name = "Имя")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Требуется поле Дата рождения")]
[Display(Name = "Дата рождения")]
[DataType(DataType.Date)]
public DateTime Birthdate { get; set; }
[Required(ErrorMessage = "Требуется поле Адрес электронной почты")]
[DataType(DataType.EmailAddress)]
[Display(Name = "Адрес электронной почты")]
public string Email { get; set; }
}
public class ExternalLogin
{
public string Provider { get; set; }
public string ProviderDisplayName { get; set; }
public string ProviderUserId { get; set; }
}
/* Мои добавления */
[Table("User")]
public class User
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Required]
public string Login { get; set; }
[Required(ErrorMessage = "Требуется поле Имя")]
[Display(Name = "Имя")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Требуется поле Фамилия")]
[Display(Name = "Фамилия")]
public string LastName { get; set; }
[Required(ErrorMessage = "Требуется поле Дата рождения")]
[Display(Name = "Дата рождения")]
[DataType(DataType.Date)]
public DateTime Birthdate { get; set; }
[Required(ErrorMessage = "Требуется поле Адрес электронной почты")]
[DataType(DataType.EmailAddress)]
[Display(Name = "Адрес электронной почты")]
public string Email { get; set; }
}
}
1.2. Разметка веб-страниц
Мастер-страница _Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewBag.Title - АИС "Библиотеки"</title>
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
<meta name="viewport" content="width=device-width" />
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<header>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title"><b>@Html.ActionLink("АИС "Библиотеки"", "Index", "Home")</b></p>
</div>
<div class="float-right">
<section id="login">
@Html.Partial("_LoginPartial")
</section>
<nav>
<ul id="menu">
<li>@Html.ActionLink("Главная", "Index", "Home")</li>
@if (User.Identity.IsAuthenticated)
{ <li>@Html.ActionLink("Библиотеки", "Index", "Library")</li> }
@if (User.Identity.IsAuthenticated)
{ <li>@Html.ActionLink("Книги", "Index", "Book")</li> }
<li>@Html.ActionLink("Контакты", "Contact", "Home")</li>
</ul>
</nav>
</div>
</div>
</header>
<div id="body">
@RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
@RenderBody()
</section>
</div>
<footer>
<div class="content-wrapper">
<div class="float-left">
<p>© @DateTime.Now.Year - АИС "Библиотеки"</p>
</div>
</div>
</footer>
@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)
@RenderSection("styles", required: false)
</body>
</html>
1.3. Дизайн веб-страниц
Дизайн страницы и стили шрифтов описаны в файле Site.css
html {
background-color: #DEB887/*#F5DEB3/*#e2e2e2*/;
margin: 0;
padding: 0;
}
body {
background-color: #F5DEB3/*#fff*/;
border-top: solid 10px #000;
color: black/*#333*/;
font-size: .85em;
font-family: "Segoe UI", Verdana, Helvetica, Sans-Serif;
margin: 0;
padding: 0;
}
a {
color: black/*#333*/;
outline: none;
padding-left: 3px;
padding-right: 3px;
text-decoration: underline;
}
a:link, a:visited,
a:active, a:hover {
color: black/*#333*/;
}
a:hover {
background-color: #cc9933/*#c7d1d6*/;
}
header, footer, hgroup,
nav, section {
display: block;
}
mark {
background-color: #a6dbed;
padding-left: 5px;
padding-right: 5px;
}
.float-left {
float: left;
}
.float-right {
float: right;
}
.clear-fix:after {
content: ".";
clear: both;
display: block;
height: 0;
visibility: hidden;
}
h1, h2, h3,
h4, h5, h6 {
color: #000;
margin-bottom: 0;
padding-bottom: 0;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.75em;
}
h3 {
font-size: 1.2em;
}
h4 {
font-size: 1.1em;
}
h5, h6 {
font-size: 1em;
}
h5 a:link, h5 a:visited, h5 a:active {
padding: 0;
text-decoration: none;
}
/* main layout
----------------------------------------------------------*/
.content-wrapper {
margin: 0 auto;
max-width: 1060px;
}
#body {
background-color: #DEB887/*#efeeef*/;
clear: both;
padding-bottom: 35px;
}
.main-content {
background: url("../Images/accent.png") no-repeat;
padding-left: 10px;
padding-top: 30px;
}
.featured + .main-content {
background: url("../Images/heroAccent.png") no-repeat;
}
header .content-wrapper {
padding-top: 20px;
}
footer {
clear: both;
background-color: #D2691E/*#CD853F*/;
font-size: .8em;
height: 50px;
}
/* site title
----------------------------------------------------------*/
.site-title {
color: black/*#c8c8c8*/;
font-family: Rockwell, Consolas, "Courier New", Courier, monospace;
font-size: 2.3em;
margin: 0;
}
.site-title a, .site-title a:hover, .site-title a:active {
background: #F5DEB3;
color: black/*#c8c8c8*/;
outline: none;
text-decoration: none;
}
/* login
----------------------------------------------------------*/
#login {
display: block;
font-size: .85em;
margin: 0 0 10px;
text-align: right;
}
#login a {
background-color: #cc9933;
margin-left: 10px;
margin-right: 3px;
padding: 2px 3px;
text-decoration: none;
}
#login a.username {
background: none;
margin: 0;
padding: 0;
text-decoration: underline;
}
#login ul {
margin: 0;
}
#login li {
display: inline;
list-style: none;
}
/* menu
----------------------------------------------------------*/
ul#menu {
font-size: 1.3em;
font-weight: 600;
margin: 0 0 5px;
padding: 0;
text-align: right;
}
ul#menu li {
display: inline;
list-style: none;
padding-left: 15px;
}
ul#menu li a {
background: none;
color: black/*#999*/;
text-decoration: none;
}
ul#menu li a:hover {
color: #333;
text-decoration: none;
}
/* page elements
----------------------------------------------------------*/
/* featured */
.featured {
background-color: #F5DEB3/*#fff*/;
}
.featured .content-wrapper {
background-color: #D2691E/*#7ac0da*/;
/*background-image: -ms-linear-gradient(left, #7ac0da 0%, #a4d4e6 100%);
background-image: -o-linear-gradient(left, #7ac0da 0%, #a4d4e6 100%);
background-image: -webkit-gradient(linear, left top, right top, color-stop(0, #7ac0da), color-stop(1, #a4d4e6));
background-image: -webkit-linear-gradient(left, #7ac0da 0%, #a4d4e6 100%);
background-image: linear-gradient(left, #7ac0da 0%, #a4d4e6 100%);*/
color: black/*#3e5667*/;
padding: 20px 40px 30px 40px;
}
.featured hgroup.title h1, .featured hgroup.title h2 {
color: black/*#fff*/;
}
.featured p {
font-size: 1.1em;
}
/* page titles */
hgroup.title {
margin-bottom: 10px;
}
hgroup.title h1, hgroup.title h2 {
display: inline;
}
hgroup.title h2 {
font-weight: normal;
margin-left: 3px;
}
/* features */
section.feature {
width: 300px;
float: left;
padding: 10px;
}
/* ordered list */
ol.round {
list-style-type: none;
padding-left: 0;
}
ol.round li {
margin: 25px 0;
padding-left: 45px;
}
ol.round li.zero {
background: url("../Images/orderedList0.png") no-repeat;
}
ol.round li.one {
background: url("../Images/orderedList1.png") no-repeat;
}
ol.round li.two {
background: url("../Images/orderedList2.png") no-repeat;
}
ol.round li.three {
background: url("../Images/orderedList3.png") no-repeat;
}
ol.round li.four {
background: url("../Images/orderedList4.png") no-repeat;
}
ol.round li.five {
background: url("../Images/orderedList5.png") no-repeat;
}
ol.round li.six {
background: url("../Images/orderedList6.png") no-repeat;
}
ol.round li.seven {
background: url("../Images/orderedList7.png") no-repeat;
}
ol.round li.eight {
background: url("../Images/orderedList8.png") no-repeat;
}
ol.round li.nine {
background: url("../Images/orderedList9.png") no-repeat;
}
/* content */
article {
float: left;
width: 70%;
}
aside {
float: right;
width: 25%;
}
aside ul {
list-style: none;
padding: 0;
}
aside ul li {
background: url("../Images/bullet.png") no-repeat 0 50%;
padding: 2px 0 2px 20px;
}
.label {
font-weight: 700;
}
/* login page */
#loginForm {
/*border-right: solid 2px #c8c8c8;*/
float: left;
width: 55%;
}
#loginForm .validation-error {
display: block;
margin-left: 15px;
}
#loginForm .validation-summary-errors ul {
margin: 0;
padding: 0;
}
#loginForm .validation-summary-errors li {
display: inline;
list-style: none;
margin: 0;
}
#loginForm input {
width: 250px;
}
#loginForm input[type="checkbox"],
#loginForm input[type="submit"],
#loginForm input[type="button"],
#loginForm button {
width: auto;
}
#socialLoginForm {
margin-left: 40px;
float: left;
width: 40%;
}
#socialLoginForm h2 {
margin-bottom: 5px;
}
#socialLoginList button {
margin-bottom: 12px;
}
#logoutForm {
display: inline;
}
/* contact */
.contact h3 {
font-size: 1.2em;
}
.contact p {
margin: 5px 0 0 10px;
}
.contact iframe {
border: 1px solid #333;
margin: 5px 0 0 10px;
}
/* forms */
fieldset {
border: none;
margin: 0;
padding: 0;
}
fieldset legend {
display: none;
}
fieldset ol {
padding: 0;
list-style: none;
}
fieldset ol li {
padding-bottom: 5px;
}
label {
display: block;
font-size: 1.2em;
font-weight: 600;
}
label.checkbox {
display: inline;
}
input, textarea {
border: 1px solid black/*#e2e2e2*/;
background: #fff;
color: black/*#333*/;
font-size: 1.2em;
margin: 5px 0 6px 0;
padding: 5px;
width: 300px;
}
textarea {
font-family: inherit;
width: 500px;
}
input:focus, textarea:focus {
border: 1px solid #7ac0da;
}
input[type="checkbox"] {
background: transparent;
border: inherit;
width: auto;
}
input[type="submit"],
input[type="button"],
button {
background-color: #F5DEB3/*#d3dce0*/;
border: 1px solid black/*#787878*/;
cursor: pointer;
font-size: 1.2em;
font-weight: 600;
padding: 7px;
margin-right: 8px;
width: auto;
}
td input[type="submit"],
td input[type="button"],
td button {
font-size: 1em;
padding: 4px;
margin-right: 4px;
}
/* info and errors */
.message-info {
border: 1px solid;
clear: both;
padding: 10px 20px;
}
.message-error {
clear: both;
color: #e80c4d;
font-size: 1.1em;
font-weight: bold;
margin: 20px 0 10px 0;
}
.message-success {
color: #7ac0da;
font-size: 1.3em;
font-weight: bold;
margin: 20px 0 10px 0;
}
.error {
color: red/*#e80c4d*/;
}
/* styles for validation helpers */
.field-validation-error {
color: #e80c4d;
font-weight: bold;
}
.field-validation-valid {
display: none;
}
input.input-validation-error {
border: 1px solid #e80c4d;
}
input[type="checkbox"].input-validation-error {
border: 0 none;
}
.validation-summary-errors {
color: #e80c4d;
font-weight: bold;
font-size: 1.1em;
}
.validation-summary-valid {
display: none;
}
/* tables
----------------------------------------------------------*/
table {
border-collapse: collapse;
border-spacing: 0;
margin-top: 0.75em;
border: 0 none;
}
th {
font-size: 1.2em;
text-align: left;
border: none 0px;
padding-left: 0;
}
th a {
display: block;
position: relative;
}
th a:link, th a:visited, th a:active, th a:hover {
color: black/*#333*/;
font-weight: 600;
text-decoration: none;
padding: 0;
}
th a:hover {
color: #000;
}
th.asc a, th.desc a {
margin-right: .75em;
}
th.asc a:after, th.desc a:after {
display: block;
position: absolute;
right: 0em;
top: 0;
font-size: 0.75em;
}
th.asc a:after {
content: ▲;
}
th.desc a:after {
content: ▼;
}
td {
padding: 0.25em 2em 0.25em 0em;
border: 0 none;
}
tr.pager td {
padding: 0 0.25em 0 0;
}
/********************
* Mobile Styles *
********************/
@media only screen and (max-width: 850px) {
/* header
----------------------------------------------------------*/
header .float-left,
header .float-right {
float: none;
}
/* logo */
header .site-title {
margin: 10px;
text-align: center;
}
/* login */
#login {
font-size: .85em;
margin: 0 0 12px;
text-align: center;
}
#login ul {
margin: 5px 0;
padding: 0;
}
#login li {
display: inline;
list-style: none;
margin: 0;
padding: 0;
}
#login a {
background: none;
color: #999;
font-weight: 600;
margin: 2px;
padding: 0;
}
#login a:hover {
color: #333;
}
/* menu */
nav {
margin-bottom: 5px;
}
ul#menu {
margin: 0;
padding: 0;
text-align: center;
}
ul#menu li {
margin: 0;
padding: 0;
}
/* main layout
----------------------------------------------------------*/
.main-content,
.featured + .main-content {
background-position: 10px 0;
}
.content-wrapper {
padding-right: 10px;
padding-left: 10px;
}
.featured .content-wrapper {
padding: 10px;
}
/* page content */
article, aside {
float: none;
width: 100%;
}
/* ordered list */
ol.round {
list-style-type: none;
padding-left: 0;
}
ol.round li {
padding-left: 10px;
margin: 25px 0;
}
ol.round li.zero,
ol.round li.one,
ol.round li.two,
ol.round li.three,
ol.round li.four,
ol.round li.five,
ol.round li.six,
ol.round li.seven,
ol.round li.eight,
ol.round li.nine {
background: none;
}
/* features */
section.feature {
float: none;
padding: 10px;
width: auto;
}
section.feature img {
color: #999;
content: attr(alt);
font-size: 1.5em;
font-weight: 600;
}
/* forms */
input {
width: 90%;
}
/* login page */
#loginForm {
border-right: none;
float: none;
width: auto;
}
#loginForm .validation-error {
display: block;
margin-left: 15px;
}
#socialLoginForm {
margin-left: 0;
float: none;
width: auto;
}
/* footer
----------------------------------------------------------*/
footer .float-left,
footer .float-right {
float: none;
}
footer {
text-align: center;
height: auto;
padding: 10px 0;
}
footer p {
margin: 0;
}
}
/* Мои классы */
.zeroQ {
color: red;
}
Стили jquery описаны в файле jquery.ui.theme.css
/*!
* jQuery UI CSS Framework 1.8.20
*
* Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
* Licensed under the MIT license.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Theming/API
*
* To view and modify this theme, visit http://jqueryui.com/themeroller/
*/
/* Component containers
----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #DEB887/*#ffffff{bgColorContent}*/ /*url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent} 50%/*{bgContentXPos} 50%/*{bgContentYPos} repeat-x*//*{bgContentRepeat}*/; color: black/*#222222{fcContent}*/; }
.ui-widget-content a { color: #222222/*{fcContent}*/; }
.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #D2691E/*#cccccc{bgColorHeader}*/ /*url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader} 50%/*{bgHeaderXPos} 50%/*{bgHeaderYPos} repeat-x*//*{bgHeaderRepeat}*/; color: black/*#222222{fcHeader}*/; font-weight: bold; }
.ui-widget-header a { color: #222222/*{fcHeader}*/; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
.ui-widget :active { outline: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-off { background-position: -96px -144px; }
.ui-icon-radio-on { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
1.4. Функциональные модули
Модуль проверки пользователей на наличие задолжностей включен в файл Global.asax.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Web;
using System.Web.Caching;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using WebMatrix.WebData;
using KP_Library.Models;
using KP_Library.Controllers;
namespace KP_Library
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
private const string DummyCacheItemKey = "NotificationCheck";
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
RegisterCacheEntry();
}
//Для рассылок
private bool RegisterCacheEntry()
{
if (null != HttpContext.Current.Cache[DummyCacheItemKey]) return false;
HttpContext.Current.Cache.Add(DummyCacheItemKey, "Notify", null,
DateTime.MaxValue, TimeSpan.FromMinutes(5),//Установить подходящее время
CacheItemPriority.Normal,
new CacheItemRemovedCallback(CacheItemRemovedCallback));
return true;
}
private const string DummyPageUrl = "http://localhost:49583/Home/Contact";
public void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
//Debug.WriteLine("Cache item callback: " + DateTime.Now.ToString());
WebClient client = new WebClient();
client.DownloadData(DummyPageUrl);
// Do the service works
//Проверить, кому и что нужно отправить.
Notifications();
}
protected void Application_BeginRequest(Object sender, EventArgs e)
{
// If the dummy page is hit, then it means we want to add another item in cache
if (HttpContext.Current.Request.Url.ToString() == DummyPageUrl)
{
// Add the item in cache and when succesful, do the work.
RegisterCacheEntry();
}
}
private void Notifications()
{
LibraryContext db = new LibraryContext();
UsersContext dbUsers = new UsersContext();
foreach (var user in dbUsers.Users)
{
foreach (var order in db.Orders.Where(o => o.UserId == user.UserId))
{
if (!order.Returned && order.ReturnBefore != null && DateTime.Compare(DateTime.Now.Date, (DateTime)order.ReturnBefore) > 0)//Книга не возвращена в срок
{
string message = string.Empty;
//Формируем текст письма
message = "Здравствуйте, " + user.FirstName + " " + user.LastName + "!";
message += Environment.NewLine;
message += "Информируем вас, что вы не вернули книгу " + order.Book.Name + " в библиотеку " + order.Library.Name + " в срок (до " + order.ReturnBefore.ToString().Substring(0, 10) + ").";
message += Environment.NewLine;
message += "Просим вас вернуть книгу.";
message += Environment.NewLine;
message += "С уважением, администрация АИС "Библиотеки"";
//Отправляем письмо
SendNotification(user.Email, message);
}
}
}
}
private void SendNotification(string to, string message)
{
MailMessage mail = new MailMessage();
mail.To.Add(new MailAddress(to));
mail.Subject = "Задолжность перед библиотекой";
mail.Body = message;
SmtpClient client = new SmtpClient();
client.Send(mail);
mail.Dispose();
}
}
}
Модуль генерации талона заказа – PdfTicket.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using KP_Library.Models;
using MigraDoc.DocumentObjectModel;
using MigraDoc.Rendering;
using PdfSharp.Pdf;
using PdfSharp.Pdf.Security;
namespace KP_Library.Functions
{
public class PdfTicket
{
public string CreateTicket(Order order)
{
Document document = CreateDocument(order);
document.UseCmykColor = true;
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(true, PdfFontEmbedding.Always);
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
//Ограничиваем права пользователя
PdfSecuritySettings securitySettings = pdfRenderer.PdfDocument.SecuritySettings;
// Setting one of the passwords automatically sets the security level to
// PdfDocumentSecurityLevel.Encrypted128Bit.
//securitySettings.UserPassword = "FlvbY";
//securitySettings.OwnerPassword = "<b,kbjntrF";
// Dont use 40 bit encryption unless needed for compatibility
//securitySettings.DocumentSecurityLevel = PdfDocumentSecurityLevel.Encrypted40Bit;
// Restrict some rights.
securitySettings.PermitAccessibilityExtractContent = false;
securitySettings.PermitAnnotations = false;
securitySettings.PermitAssembleDocument = false;
securitySettings.PermitExtractContent = false;
securitySettings.PermitFormsFill = false;
securitySettings.PermitFullQualityPrint = true;
securitySettings.PermitModifyDocument = false;
securitySettings.PermitPrint = true;
//
string filename = order.UserLastName + "_" + order.UserFirstName + "_" + order.DateOfOrder.ToString().Substring(0, 10).Replace(., -) + ".pdf";
string targetFolder = HttpContext.Current.Server.MapPath("~/tickets");
string filepath = Path.Combine(targetFolder, filename);
pdfRenderer.PdfDocument.Save(filepath);
return filepath;
}
public Document CreateDocument(Order order)
{
// Create a new MigraDoc document
Document document = new Document();
// Add a section to the document
Section section = document.AddSection();
section.PageSetup.PageFormat = PageFormat.A6;//стандартный размер страницы
section.PageSetup.Orientation = Orientation.Portrait;//ориентация
section.PageSetup.BottomMargin = 10;//нижний отступ
section.PageSetup.TopMargin = 10;//верхний отступ
section.PageSetup.LeftMargin = 15;
section.PageSetup.RightMargin = 10;
Paragraph parTitle = section.AddParagraph();
parTitle.Format.Font.Color = Color.FromCmyk(0, 0, 0, 255);
parTitle.Format.Font.Size = Unit.FromPoint(16);
parTitle.Format.Alignment = ParagraphAlignment.Center;
parTitle.AddFormattedText("АИС "Библиотеки"", TextFormat.Bold);
Paragraph mainPar = section.AddParagraph();
mainPar.Format.Font.Size = Unit.FromPoint(14);
mainPar.AddFormattedText("
");
mainPar.AddFormattedText("ФИО
", TextFormat.Bold);
mainPar.AddFormattedText(order.UserLastName + " " + order.UserFirstName + "
");
mainPar.AddFormattedText("Библиотека
", TextFormat.Bold);
mainPar.AddFormattedText("Название: " + order.Library.Name + "
");
mainPar.AddFormattedText(" Адрес: " + order.Library.Adress + "
");
mainPar.AddFormattedText("Книга
", TextFormat.Bold);
mainPar.AddFormattedText("Автор: " + order.Book.Author + "
");
mainPar.AddFormattedText("Название: " + order.Book.Name + "
");
mainPar.AddFormattedText("ISBN: " + order.Book.ISBN + "
");
return document;
}
}
}
Модуль перенаправления при попытке открыть страницу с недостаточными для этого правами доступа – HttpForbiddenResult.cs
using System.Net;
using System.Web.Mvc;
namespace KP_Library.Functions
{
public class HttpForbiddenResult : HttpStatusCodeResult
{
public override void ExecuteResult(ControllerContext context)
{
base.ExecuteResult(context);
// creates the ViewResult adding ViewData and TempData parameters
ViewResult result = new ViewResult
{
ViewName = "AccessDenied",
ViewData = context.Controller.ViewData,
TempData = context.Controller.TempData
};
result.ExecuteResult(context);
}
// calls the base constructor with 403 status code
public HttpForbiddenResult()
: base(HttpStatusCode.Forbidden, "Forbidden")
{
}
}
}
Контроллеры.
AccountController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;
using KP_Library.Filters;
using KP_Library.Models;
namespace KP_Library.Controllers
{
[Authorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
//
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.Login, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "Неверный пароль или имя пользователя.");
return View(model);
}
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
WebSecurity.Logout();
return RedirectToAction("Index", "Home");
}
//
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount(model.Login, model.Password, new { LastName = model.LastName, FirstName = model.FirstName, Birthdate = model.Birthdate, Email = model.Email });
WebSecurity.Login(model.Login, model.Password);
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/Disassociate
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Disassociate(string provider, string providerUserId)
{
string ownerAccount = OAuthWebSecurity.GetUserName(provider, providerUserId);
ManageMessageId? message = null;
// Only disassociate the account if the currently logged in user is the owner
if (ownerAccount == User.Identity.Name)
{
// Use a transaction to prevent the user from deleting their last login credential
using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
{
bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
if (hasLocalAccount || OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name).Count > 1)
{
OAuthWebSecurity.DeleteAccount(provider, providerUserId);
scope.Complete();
message = ManageMessageId.RemoveLoginSuccess;
}
}
}
return RedirectToAction("Manage", new { Message = message });
}
//
// GET: /Account/Manage
//Сделать полный профиль.
public ActionResult Manage(ManageMessageId? message)
{
ViewBag.StatusMessage =
message == ManageMessageId.ChangePasswordSuccess ? "Ваш пароль был изменен."
: message == ManageMessageId.SetPasswordSuccess ? "Ваш пароль был установлен."
: message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
: "";
ViewBag.HasLocalPassword = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
ViewBag.ReturnUrl = Url.Action("Manage");
ViewBag.UserId = (int)Membership.GetUser().ProviderUserKey;
return View();
}
//
// POST: /Account/Manage
//По сути смена пароля
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Manage(LocalPasswordModel model)
{
bool hasLocalAccount = OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
ViewBag.HasLocalPassword = hasLocalAccount;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasLocalAccount)
{
if (ModelState.IsValid)
{
// ChangePassword will throw an exception rather than return false in certain failure scenarios.
bool changePasswordSucceeded;
try
{
changePasswordSucceeded = WebSecurity.ChangePassword(User.Identity.Name, model.OldPassword, model.NewPassword);
}
catch (Exception)
{
changePasswordSucceeded = false;
}
if (changePasswordSucceeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
}
else
{
ModelState.AddModelError("", "Неверно указан старый пароль и новый пароль не корректен.");
}
}
}
else
{
// User does not have a local password so remove any validation errors caused by a missing
// OldPassword field
ModelState state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
try
{
WebSecurity.CreateAccount(User.Identity.Name, model.NewPassword);
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
catch (Exception e)
{
ModelState.AddModelError("", e);
}
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
return new ExternalLoginResult(provider, Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
}
//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public ActionResult ExternalLoginCallback(string returnUrl)
{
AuthenticationResult result = OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
if (!result.IsSuccessful)
{
return RedirectToAction("ExternalLoginFailure");
}
if (OAuthWebSecurity.Login(result.Provider, result.ProviderUserId, createPersistentCookie: false))
{
return RedirectToLocal(returnUrl);
}
if (User.Identity.IsAuthenticated)
{
// If the current user is logged in add the new account
OAuthWebSecurity.CreateOrUpdateAccount(result.Provider, result.ProviderUserId, User.Identity.Name);
return RedirectToLocal(returnUrl);
}
else
{
// User is new, ask for their desired membership name
string loginData = OAuthWebSecurity.SerializeProviderUserId(result.Provider, result.ProviderUserId);
ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(result.Provider).DisplayName;
ViewBag.ReturnUrl = returnUrl;
return View("ExternalLoginConfirmation", new RegisterExternalLoginModel { Login = result.UserName, ExternalLoginData = loginData });
}
}
//
// POST: /Account/ExternalLoginConfirmation
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)
{
string provider = null;
string providerUserId = null;
if (User.Identity.IsAuthenticated || !OAuthWebSecurity.TryDeserializeProviderUserId(model.ExternalLoginData, out provider, out providerUserId))
{
return RedirectToAction("Manage");
}
if (ModelState.IsValid)
{
// Insert a new user into the database
using (UsersContext db = new UsersContext())
{
User user = db.Users.FirstOrDefault(u => u.Login.ToLower() == model.Login.ToLower());
// Check if user already exists
if (user == null)
{
// Insert name into the profile table
db.Users.Add(new User { Login = model.Login });
db.SaveChanges();
OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.Login);
OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("UserName", "User name already exists. Please enter a different user name.");
}
}
}
ViewBag.ProviderDisplayName = OAuthWebSecurity.GetOAuthClientData(provider).DisplayName;
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
//
// GET: /Account/ExternalLoginFailure
[AllowAnonymous]
public ActionResult ExternalLoginFailure()
{
return View();
}
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return PartialView("_ExternalLoginsListPartial", OAuthWebSecurity.RegisteredClientData);
}
[ChildActionOnly]
public ActionResult RemoveExternalLogins()
{
ICollection<OAuthAccount> accounts = OAuthWebSecurity.GetAccountsFromUserName(User.Identity.Name);
List<ExternalLogin> externalLogins = new List<ExternalLogin>();
foreach (OAuthAccount account in accounts)
{
AuthenticationClientData clientData = OAuthWebSecurity.GetOAuthClientData(account.Provider);
externalLogins.Add(new ExternalLogin
{
Provider = account.Provider,
ProviderDisplayName = clientData.DisplayName,
ProviderUserId = account.ProviderUserId,
});
}
ViewBag.ShowRemoveButton = externalLogins.Count > 1 || OAuthWebSecurity.HasLocalAccount(WebSecurity.GetUserId(User.Identity.Name));
return PartialView("_RemoveExternalLoginsPartial", externalLogins);
}
#region Helpers
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
}
internal class ExternalLoginResult : ActionResult
{
public ExternalLoginResult(string provider, string returnUrl)
{
Provider = provider;
ReturnUrl = returnUrl;
}
public string Provider { get; private set; }
public string ReturnUrl { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
}
}
private static string ErrorCodeToString(MembershipCreateStatus createStatus)
{
// See http://go.microsoft.com/fwlink/?LinkID=177550 for
// a full list of status codes.
switch (createStatus)
{
case MembershipCreateStatus.DuplicateUserName:
return "User name already exists. Please enter a different user name.";
case MembershipCreateStatus.DuplicateEmail:
return "A user name for that e-mail address already exists. Please enter a different e-mail address.";
case MembershipCreateStatus.InvalidPassword:
return "The password provided is invalid. Please enter a valid password value.";
case MembershipCreateStatus.InvalidEmail:
return "The e-mail address provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidAnswer:
return "The password retrieval answer provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidQuestion:
return "The password retrieval question provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.InvalidUserName:
return "The user name provided is invalid. Please check the value and try again.";
case MembershipCreateStatus.ProviderError:
return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
case MembershipCreateStatus.UserRejected:
return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
default:
return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
}
}
#endregion
}
}
BookController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using KP_Library.Models;
namespace KP_Library.Controllers
{
public class BookController : Controller
{
private LibraryContext db = new LibraryContext();
//
// GET: /Book/
[Authorize]
public ActionResult Index()
{
return View();
}
//
// GET: /Book/Details/5
[Authorize]
public ActionResult Details(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (User.IsInRole("admin") || db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
ViewBag.AdminRight = true;
}
else
{
ViewBag.AdminRight = false;
}
Book book = db.Books.Find(id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
//
// GET: /Book/Create
[Authorize(Roles = "admin, librarian")]
public ActionResult Create()
{
return View();
}
//
// POST: /Book/Create
[HttpPost]
[Authorize(Roles = "admin, librarian")]
public ActionResult Create(Book book, HttpPostedFileBase image)
{
if (image != null && image.ContentType != "image/jpeg" && image.ContentType != "image/png")
{
ModelState.AddModelError("", "Изображение должно иметь расширение ".jpg" или ".png"!");
}
if (book.YearOfPublishing > DateTime.Now.Year)
{
ModelState.AddModelError("", "Год издания книги не может быть позднее текущего года: " + DateTime.Now.Year + "!");
}
if (ModelState.IsValid)
{
if (image != null)//Сохранять файл не в БД?
{
book.ImageMimeType = image.ContentType;
book.ImageData = new byte[image.ContentLength];
image.InputStream.Read(book.ImageData, 0, image.ContentLength);
}
db.Books.Add(book);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
//
// GET: /Book/Edit/5
[Authorize(Roles = "admin, librarian")]
public ActionResult Edit(int id = 0)
{
Book book = db.Books.Find(id);
if (book == null)
{
return HttpNotFound();
}
return View(book);
}
//
// POST: /Book/Edit/5
[Authorize(Roles="admin, librarian")]
[HttpPost]
public ActionResult Edit(Book book, HttpPostedFileBase image)
{
if (image != null && image.ContentType != "image/jpeg" && image.ContentType != "image/png")
{
ModelState.AddModelError("", "Изображение должно иметь расширение ".jpg" или ".png"!");
}
if (book.YearOfPublishing > DateTime.Now.Year)
{
ModelState.AddModelError("", "Год издания книги не может быть позднее текущего года: " + DateTime.Now.Year + "!");
}
if (ModelState.IsValid)
{
if (image != null)
{
book.ImageMimeType = image.ContentType;
book.ImageData = new byte[image.ContentLength];
image.InputStream.Read(book.ImageData, 0, image.ContentLength);
}
db.Entry(book).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(book);
}
//
// POST: /Book/Delete/5
[Authorize(Roles="admin")]
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Book book = db.Books.Find(id);
db.Books.Remove(book);
db.SaveChanges();
return RedirectToAction("Index");
}
[Authorize(Roles = "admin")]
[HttpGet]
public PartialViewResult DeleteConfirmation(string id)
{
ViewBag.BookId = id;
return PartialView("_DeleteConfirmation");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
[Authorize]
public PartialViewResult BooksList(string id = "Название", string searchField = "Названию", string search = "")
{
//Сортируем по столбцу id
//Ищем по search в searchField
IEnumerable<Book> Books = db.Books.ToList();
search = search.ToUpperInvariant();
switch (id)
{
case "Название":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Name);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.Name);
break;
}
break;
case "Автор":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Author);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.Author);
break;
}
break;
case "Издательство":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.PublishingHouse);
break;
}
break;
case "Год издания":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
}
break;
case "Тематика":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Subject);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.Subject);
break;
}
break;
case "ISBN":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Автору":
Books = Books.Where(b => b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Издательству":
Books = Books.Where(b => b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Году издания":
Books = Books.Where(b => b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Тематике":
Books = Books.Where(b => b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "ISBN":
Books = Books.Where(b => b.ISBN.Contains(search)).OrderBy(b => b.ISBN);
break;
}
break;
}
ViewBag.SearchField = searchField;
ViewBag.Search = search;
return PartialView("_BooksList", Books);
}
[Authorize]
public PartialViewResult ChooseBooksList(string id = "Название", string searchField = "Названию", string search = "", int LibraryId = 0)
{
IEnumerable<Book> Books = db.Books.ToList();
Library lib = db.Libraries.FirstOrDefault(l => l.LibraryId == LibraryId);//Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId))
search = search.ToUpperInvariant();
switch (id)
{
case "Название":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Name);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.Name);
break;
}
break;
case "Автор":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Author);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Author);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.Author);
break;
}
break;
case "Издательство":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.PublishingHouse);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.PublishingHouse);
break;
}
break;
case "Год издания":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.YearOfPublishing);
break;
}
break;
case "Тематика":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.Subject);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.Subject);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.Subject);
break;
}
break;
case "ISBN":
switch (searchField)
{
case "Названию":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Автору":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Author.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Издательству":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.PublishingHouse.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Году издания":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.YearOfPublishing.ToString().Contains(search)).OrderBy(b => b.ISBN);
break;
case "Тематике":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.Subject.ToUpperInvariant().Contains(search)).OrderBy(b => b.ISBN);
break;
case "ISBN":
Books = Books.Where(b => !b.BooksInLibrary.Any(bil => bil.LibraryId == LibraryId) && b.ISBN.Contains(search)).OrderBy(b => b.ISBN);
break;
}
break;
}
ViewBag.SearchField = searchField;
ViewBag.Search = search;
ViewBag.LibraryId = LibraryId;
return PartialView("_ChooseBooksList", Books);
}
[Authorize]
[Authorize(Roles = "admin, librarian")]
public FileContentResult GetImage(int BookId)
{
Book book = db.Books.FirstOrDefault(b => b.BookId == BookId);
if (book != null)
{
return File(book.ImageData, book.ImageMimeType);
}
else
{
return null;
}
}
[Authorize]
[Authorize(Roles = "admin, librarian")]
public ActionResult ChooseBook(int LibraryId = 0)
{
ViewBag.LibraryId = LibraryId;
return View();
}
}
}
BookInLibraryController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using KP_Library.Models;
using System.Web.Security;
using KP_Library.Functions;
namespace KP_Library.Controllers
{
public class BookInLibraryController : Controller
{
private LibraryContext db = new LibraryContext();
//
// GET: /BookInLibrary/IndexForLibrary/5
[Authorize]
public ActionResult IndexForLibrary(int id, string ReturnUrl = "")
{
var booksinlibrary = db.BooksInLibrary.Where(bil => bil.LibraryId == id).OrderBy(bil => bil.Book.Name).Include(b => b.Library).Include(b => b.Book);
ViewBag.LibraryId = id;
ViewBag.LibraryName = db.Libraries.Find(id).Name;
return View(booksinlibrary.ToList());
}
//
// GET: /BookInLibrary/IndexForBook/5
[Authorize]
public ActionResult IndexForBook(int id, string ReturnUrl = "")
{
var booksinlibrary = db.BooksInLibrary.Where(bil => bil.BookId == id).OrderBy(bil => bil.Library.Name).Include(b => b.Library).Include(b => b.Book);
ViewBag.BookId = id;
ViewBag.BookName = db.Books.Find(id).Name;
return View(booksinlibrary.ToList());
}
[Authorize]
public ActionResult _EmptyList(string ReturnUrl)
{
ViewBag.ReturnUrl = ReturnUrl;
return View();
}
//
// GET: /BookInLibrary/Details/5
[Authorize]
public ActionResult Details(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (User.IsInRole("admin") || db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
ViewBag.AdminRight = true;
}
else
{
ViewBag.AdminRight = false;
}
BookInLibrary bookinlibrary = db.BooksInLibrary.Find(id);
if (bookinlibrary == null)
{
return HttpNotFound();
}
return View(bookinlibrary);
}
//
// GET: /BookInLibrary/Create
[Authorize]
public ActionResult Create(int BookId = 0, int LibraryId = 0)
{
if (BookId == 0)
{
//ViewBag.LibraryId = LibraryId;
return RedirectToAction("ChooseBook", "Book", new { LibraryId = LibraryId } );
}
if (LibraryId == 0)
{
//ViewBag.BookId = BookId;
return RedirectToAction("ChooseLibrary", "Library", new { BookId = LibraryId });
}
Book book = db.Books.FirstOrDefault(l => l.BookId == BookId);
ViewBag.BookId = book.BookId;
ViewBag.BookName = book.Name;
Library lib = db.Libraries.FirstOrDefault(l => l.LibraryId == LibraryId);
ViewBag.LibraryId = lib.LibraryId;
ViewBag.LibraryName = lib.Name;
//ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name");
//ViewBag.BookId = new SelectList(db.Books, "BookId", "Name");
return View();
}
//
// POST: /BookInLibrary/Create
[Authorize]
[HttpPost]
public ActionResult Create(BookInLibrary bookinlibrary)
{
if (ModelState.IsValid)
{
//bookinlibrary.Library.TotalUniqueBooks += 1;
db.BooksInLibrary.Add(bookinlibrary);
db.SaveChanges();
//Увеличить число книг в библиотеке
Library libr = db.Libraries.Find(bookinlibrary.LibraryId);
libr.TotalUniqueBooks = libr.TotalUniqueBooks + 1;
db.Entry(libr).State = EntityState.Modified;
db.SaveChanges();
//По умолчанию все книги в этой же библиотеке
return RedirectToAction("IndexForLibrary", new { id = bookinlibrary.LibraryId });
}
//ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", bookinlibrary.LibraryId);
//ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", bookinlibrary.BookId);
Book book = db.Books.FirstOrDefault(l => l.BookId == bookinlibrary.BookId);
ViewBag.BookId = book.BookId;
ViewBag.BookName = book.Name;
Library lib = db.Libraries.FirstOrDefault(l => l.LibraryId == bookinlibrary.LibraryId);
ViewBag.LibraryId = lib.LibraryId;
ViewBag.LibraryName = lib.Name;
return View(bookinlibrary);
}
//
// GET: /BookInLibrary/Edit/5
[Authorize]
public ActionResult Edit(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
BookInLibrary bookinlibrary = db.BooksInLibrary.Find(id);
if (bookinlibrary == null)
{
return HttpNotFound();
}
ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", bookinlibrary.LibraryId);
ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", bookinlibrary.BookId);
return View(bookinlibrary);
}
//
// POST: /BookInLibrary/Edit/5
//Отредактировать
[Authorize]
[HttpPost]
public ActionResult Edit(BookInLibrary bookinlibrary)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!HttpContext.User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == bookinlibrary.Library.LibraryId))
{
return new HttpForbiddenResult();
}
if (ModelState.IsValid)
{
db.Entry(bookinlibrary).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = bookinlibrary.BookInLibraryId });
}
ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", bookinlibrary.LibraryId);
ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", bookinlibrary.BookId);
return View(bookinlibrary);
}
[Authorize]
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!HttpContext.User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
BookInLibrary bil = db.BooksInLibrary.Find(id);
//Уменьшить число книг в библиотеке
Library libr = db.Libraries.Find(bil.LibraryId);
libr.TotalUniqueBooks = libr.TotalUniqueBooks - 1;
db.Entry(libr).State = EntityState.Modified;
db.SaveChanges();
//
db.BooksInLibrary.Remove(bil);
db.SaveChanges();
return RedirectToAction("IndexForLibrary", new { id = bil.LibraryId });
}
[Authorize]
[HttpGet]
public PartialViewResult DeleteConfirmation(string id)
{
ViewBag.BookInLibraryId = id;
return PartialView("_DeleteConfirmation");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
}
HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using KP_Library.Filters;
namespace KP_Library.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
//ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult Contact()
{
//ViewBag.Message = "Your contact page.";
return View();
}
}
}
LibraryController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using KP_Library.Models;
using KP_Library.Functions;
namespace KP_Library.Controllers
{
public class LibraryController : Controller
{
private LibraryContext db = new LibraryContext();
//
// GET: /Library/
[Authorize]
public ActionResult Index()
{
return View();
}
//
// GET: /Library/Details/5
[Authorize]
public ActionResult Details(int id = 0)
{
Library library = db.Libraries.Find(id);
if (library == null)
{
return HttpNotFound();
}
int userId = (int)Membership.GetUser().ProviderUserKey;
if (HttpContext.User.IsInRole("admin") || db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
ViewBag.AdminRight = true;
}
else
{
ViewBag.AdminRight = false;
}
return View(library);
}
//
// GET: /Library/Create
[Authorize(Roles="admin")]
public ActionResult Create()
{
return View();
}
//
// POST: /Library/Create
[Authorize(Roles = "admin")]
[HttpPost]
public ActionResult Create(Library library)
{
if (ModelState.IsValid)
{
library.TotalUniqueBooks = 0;
db.Libraries.Add(library);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(library);
}
//
// GET: /Library/Edit/5
[Authorize]
public ActionResult Edit(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!HttpContext.User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
Library library = db.Libraries.Find(id);
if (library == null)
{
return HttpNotFound();
}
return View(library);
}
//
// POST: /Library/Edit/5
[Authorize]
[HttpPost]
public ActionResult Edit(Library library)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == library.LibraryId))
{
return new HttpForbiddenResult();
}
if (ModelState.IsValid)
{
db.Entry(library).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = library.LibraryId });
}
return View(library);
}
//
// POST: /Library/Delete/5
[Authorize(Roles = "admin")]
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Library library = db.Libraries.Find(id);
db.Libraries.Remove(library);
db.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
[Authorize]
public PartialViewResult DeleteConfirmation(string id)
{
ViewBag.LibraryId = id;
return PartialView("_DeleteConfirmation");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
[Authorize]
public PartialViewResult LibrariesList(string id = "Название", string searchField = "Названию", string search = "")
{
IEnumerable<Library> Libraries = db.Libraries.ToList();
search = search.ToUpperInvariant();
switch (id)
{
case "Название":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Адресу":
Libraries = Libraries.Where(l => l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
}
break;
case "Адрес":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Adress);
break;
case "Адресу":
Libraries = Libraries.Where(l => l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.Adress);
break;
}
break;
case "Число уникальных наименований":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.TotalUniqueBooks);
break;
case "Адресу":
Libraries = Libraries.Where(l => l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.TotalUniqueBooks);
break;
}
break;
}
ViewBag.SearchField = searchField;
ViewBag.Search = search;
return PartialView("_LibrariesList", Libraries);
}
[Authorize]
public PartialViewResult ChooseLibrariesList(string id = "Название", string searchField = "Названию", string search = "", int BookId = 0)
{
IEnumerable<Library> Libraries = db.Libraries.ToList();
search = search.ToUpperInvariant();
switch (id)
{
case "Название":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
case "Адресу":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.Name);
break;
}
break;
case "Адрес":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.Adress);
break;
case "Адресу":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.Adress);
break;
}
break;
case "Число уникальных наименований":
switch (searchField)
{
case "Названию":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Name.ToUpperInvariant().Contains(search)).OrderBy(b => b.TotalUniqueBooks);
break;
case "Адресу":
Libraries = Libraries.Where(l => !l.BooksInLibrary.Any(bil => bil.BookId == BookId) && l.Adress.ToUpperInvariant().Contains(search)).OrderBy(b => b.TotalUniqueBooks);
break;
}
break;
}
ViewBag.SearchField = searchField;
ViewBag.Search = search;
ViewBag.BookId = BookId;
return PartialView("_ChooseLibrariesList", Libraries);
}
[Authorize]
public ActionResult ChooseLibrary(int BookId = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
IQueryable<int> availLibIDs = db.UsersInLibrary.Where(uil => uil.UserId == userId).Select(uil => uil.LibraryID);
IQueryable<Library> Libraries = db.Libraries.Where(l => availLibIDs.Contains(l.LibraryId));
ViewBag.BookId = BookId;
return View(Libraries.ToList());
}
}
}
OrderController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Objects;
using System.Linq;
using System.Net.Mail;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using KP_Library.Functions;
using KP_Library.Models;
namespace KP_Library.Controllers
{
public class OrderController : Controller
{
private LibraryContext db = new LibraryContext();
private UsersContext db_users = new UsersContext();
//
// GET: /Order/IndexForLibrary/2
[Authorize]
public ActionResult IndexForLibrary(int id, string ReturnUrl = "")
{
var orders = db.Orders.Where(o => o.LibraryId == id).OrderBy(o => o.DateOfOrder).Include(o => o.Library).Include(o => o.Book);
if (orders.Count() == 0)
{
return RedirectToAction("_EmptyList", new { ReturnUrl = ReturnUrl });
}
return View(orders.ToList());
}
//
// GET: /Order/IndexForUser/2
[Authorize]
public ActionResult IndexForUser(int id, string ReturnUrl = "")
{
if (!HttpContext.User.IsInRole("admin") && (int)Membership.GetUser().ProviderUserKey != id)
{
return new KP_Library.Functions.HttpForbiddenResult();
}
var orders = db.Orders.Where(o => o.UserId == id).Include(o => o.Library).Include(o => o.Book);
if (orders.Count() == 0)
{
return RedirectToAction("_EmptyList", new { ReturnUrl = ReturnUrl });
}
return View(orders.ToList());
}
//
// GET: /Order/Details/5
[Authorize]
public ActionResult Details(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (HttpContext.User.IsInRole("admin") || db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
ViewBag.AdminRight = true;
}
else
{
ViewBag.AdminRight = false;
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
ViewBag.UserId = order.UserId;
return View(order);
}
//
// GET: /Order/Create/1
[Authorize]
public ActionResult Create(int id)
{
//ViewBag.BookId = new SelectList(db.Books, "BookId", "Name");
//ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name");
BookInLibrary bil = db.BooksInLibrary.Find(id);
Book book = db.Books.FirstOrDefault(l => l.BookId == bil.BookId);
ViewBag.BookId = book.BookId;
ViewBag.BookName = book.Name;
Library lib = db.Libraries.FirstOrDefault(l => l.LibraryId == bil.LibraryId);
ViewBag.LibraryId = lib.LibraryId;
ViewBag.LibraryName = lib.Name;
return View();
}
//
// POST: /Order/Create
[Authorize]
[HttpPost]
public ActionResult Create(Order order)
{
order.UserId = (int)Membership.GetUser().ProviderUserKey;
//order.UserLogin = Membership.GetUser().UserName;
User user = db_users.Users.Find(order.UserId);
order.UserLastName = user.LastName;
order.UserFirstName = user.FirstName;
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
Book book = db.Books.Find(order.BookId);
Library lib = db.Libraries.Find(order.LibraryId);
BookInLibrary bil = book.BooksInLibrary.Intersect(lib.BooksInLibrary).FirstOrDefault();
bil.CurrentQuantity = bil.CurrentQuantity - 1;
db.Entry(bil).State = EntityState.Modified;
db.SaveChanges();
//Талончик
PdfTicket pdf = new PdfTicket();
string filepath = pdf.CreateTicket(order);
//Отправляем письмо
MailMessage mail = new MailMessage();
mail.To.Add(new MailAddress(user.Email));
mail.Subject = "Талон заказа";
string message = "Здравствуйте, " + user.FirstName + " " + user.LastName + "!";
message += Environment.NewLine;
message += "Отправляем вам ваш талон заказа.";
message += Environment.NewLine;
message += "С уважением, администрация АИС "Библиотеки"";
mail.Body = message;
//if (!string.IsNullOrEmpty(attachFile))
mail.Attachments.Add(new Attachment(filepath));
SmtpClient client = new SmtpClient();
client.Send(mail);
mail.Dispose();
//Удаляем файл.
System.IO.File.Delete(filepath);
//
return RedirectToAction("IndexForUser", new { id = order.UserId });
}
ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", order.BookId);
ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", order.LibraryId);
return View(order);
}
//
// GET: /Order/Edit/5
[Authorize]
public ActionResult Edit(int id = 0)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!HttpContext.User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
Order order = db.Orders.Find(id);
if (order == null)
{
return HttpNotFound();
}
ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", order.BookId);
ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", order.LibraryId);
ViewBag.UserId = order.UserId;
return View(order);
}
//
// POST: /Order/Edit/5
[Authorize]
[HttpPost]
public ActionResult Edit(Order order)
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!HttpContext.User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == order.LibraryId))
{
return new HttpForbiddenResult();
}
if (order.DateOfReturn != null)
{
order.Returned = true;
Book book = db.Books.Find(order.BookId);
Library lib = db.Libraries.Find(order.LibraryId);
BookInLibrary bil = book.BooksInLibrary.Intersect(lib.BooksInLibrary).FirstOrDefault();
bil.CurrentQuantity = bil.CurrentQuantity + 1;
db.Entry(bil).State = EntityState.Modified;
db.SaveChanges();
}
if (ModelState.IsValid)
{
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = order.OrderId });
}
ViewBag.BookId = new SelectList(db.Books, "BookId", "Name", order.BookId);
ViewBag.LibraryId = new SelectList(db.Libraries, "LibraryId", "Name", order.LibraryId);
return View(order);
}
//
// POST: /Order/Delete/5
[Authorize]
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Order order = db.Orders.Find(id);
int userId = (int)Membership.GetUser().ProviderUserKey;
if (userId != order.UserId || (!order.Returned && order.DateOfIssue != null))
{
return new HttpForbiddenResult();
}
if (!order.Returned)
{
Book book = db.Books.Find(order.BookId);
Library lib = db.Libraries.Find(order.LibraryId);
BookInLibrary bil = book.BooksInLibrary.Intersect(lib.BooksInLibrary).FirstOrDefault();
bil.CurrentQuantity = bil.CurrentQuantity + 1;
db.Entry(bil).State = EntityState.Modified;
db.SaveChanges();
}
db.Orders.Remove(order);
db.SaveChanges();
return RedirectToAction("IndexForUser", new { id = order.UserId });
}
[Authorize]
[HttpGet]
public PartialViewResult DeleteConfirmation(string id)
{
ViewBag.OrderId = id;
return PartialView("_DeleteConfirmation");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
[Authorize]
public ActionResult IssuedBooks(int id, string ReturnUrl = "")
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
IEnumerable<Order> orders = db.Orders.Where(o => o.LibraryId == id && o.DateOfIssue != null).Include(o => o.Library).Include(o => o.Book);
if (orders.Count() == 0)
{
return RedirectToAction("_EmptyList", new { ReturnUrl = ReturnUrl });
}
return View(orders.OrderBy(o => o.UserLastName).ToList());
}
[Authorize]
public ActionResult DebtorsList(int id, string ReturnUrl = "")
{
int userId = (int)Membership.GetUser().ProviderUserKey;
if (!User.IsInRole("admin") && !db.UsersInLibrary.Any(ul => ul.UserId == userId && ul.LibraryID == id))
{
return new HttpForbiddenResult();
}
List<int> ordersId = new List<int>();
List<Order> orders = new List<Order>();
foreach (var order in db.Orders)
{
if (!order.Returned && order.ReturnBefore != null && DateTime.Compare(DateTime.Now.Date, (DateTime)order.ReturnBefore) > 0)//Книга не возвращена в срок
{
ordersId.Add(order.OrderId);
}
}
foreach (var ordId in ordersId)
{
orders.Add(db.Orders.Where(o => o.OrderId == ordId).Include(o => o.Library).Include(o => o.Book).FirstOrDefault());
}
if (orders.Count() == 0)
{
return RedirectToAction("_EmptyList", new { ReturnUrl = ReturnUrl });
}
return View(orders.OrderBy(o => o.UserLastName));
}
[Authorize]
public ActionResult _EmptyList(string ReturnUrl)
{
ViewBag.ReturnUrl = ReturnUrl;
return View();
}
}
}
UserController.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using KP_Library.Models;
namespace KP_Library.Controllers
{
public class UserController : Controller
{
private UsersContext usersDb = new UsersContext();
//
// GET: /User/
//
public PartialViewResult _UserData()
{
int userId = (int)Membership.GetUser().ProviderUserKey;
KP_Library.Models.User user = usersDb.Users.Find(userId);
return PartialView(user);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ManageData(User user)
{
if (ModelState.IsValid)
{
usersDb.Entry(user).State = EntityState.Modified;
usersDb.SaveChanges();
return RedirectToAction("Manage", "Account", new { Message = "Личные данные изменены." });
}
return RedirectToAction("Manage", "Account",new { Message = "Ошибка при заполнении формы." });
}
}
}
Автоматизированная информационная библиотечная система АИС “Библиотеки”
Дипломная работа по предмету «Программирование»