Программное средство по обмену услугами для владельцев собак

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

Программное средство по обмену услугами для владельцев собак

Министерство образования Республики Беларусь

Учреждение образования «Белорусский государственный университет информатики и радиоэлектроники»

Институт информационных технологий

Кафедра «Микропроцессорные системы и сети»

 







ПОЯСНИТЕЛЬНАЯ ЗАПИСКА

К ДИПЛОМНОМУ ПРОЕКТУ

НА ТЕМУ:

«Программное средство по обмену услугами для владельцев собак»


Дипломник Е.Г. Хомич

Руководитель Е.Н. Шнейдеров

Консультанты:

по ЕСПД и ЕСКД В.Н. Мухаметов


МИНСК 2016

ЗАДАНИЕ по дипломному проектированию

Слушателю Хомичу Евгению Геннадьевичу

.Тема проекта «Программное средство по обмену услугами для владельцев собак», утверждена приказом по Институту № 120 - С от 7 июля 2016 г.

2. Сроки сдачи слушателем законченного проекта 11 октября 2016 г.

3. Исходные данные к проекту Сервис реализуется для пользователей сети интернет, планирующих обмен услугами, осуществляет удобный поиск и сортировку объявлений - Google Chrome; Система должна быть построена с применением технологии ASP.NET MVC. В качестве средства хранения и источника данных в приложении использовать базу данных Microsoft SQL Server.

. Перечень подлежащих разработке вопросов:

1) Аналитический обзор приложений для тестирования знаний, и постановка задачи;

) Методы и модели, положенные в основу проекта;

) Разработка проекта программного обеспечения;

) Разработка алгоритмов и их программная реализация;

) Тестирование полученного программного продукта.

5. Перечень графического материала (с точным указанием обязательных чертежей и графиков):

1) Схема ресурсов системы, ф. А3, чертеж.

) Схема работы системы, ф. А2, чертеж.

) Схема программы (по выбору), 2шт., ф. А3, чертеж.

6. Консультанты по проекту (с указанием относящихся к ним разделов проекта)

по ЕСПД, ЕСКД - В. Н. Мухаметов

по специальности - В. Н. Мухаметов

7. Дата выдачи задания 7 июня 2016 г.

. Календарный график работы над проектом на весь период проектирования

.08.2016 г. - 25 % (пп. 4.1-4.2)

.08.2016 г. - 50 % (п. 4.3)

.09.2016 г. - 75 % (пп. 4.4,4.5)

.09.2016 г. - 100 % (п.4 полностью, п.5 и оформление ПЗ)

Руководитель (подпись, Ф.И.О., должность) ( Шнейдеров Е.Н., ассистент каф. МПСС).

Задание принял к исполнению (дата и подпись слушателя) 7 июня 2016 г.

Содержание

Введение

1. Аналитический обзор и постановка задачи

. Методы и модели, положенные в основу проекта

2.1       Задание критериев отбора объявлений по фильтрам (любой пользователь, в том числе неавторизированный)

.2         Редактирование личных данных (авторизированный пользователь)

.3         Редактирование объявления (авторизированный пользователь)

.4         Редактирование питомца (авторизированный пользователь)

.5         Создание нового объявления (авторизированный пользователь)

.6         Добавление нового питомца (авторизированный пользователь)

.7         Отправка личного сообщения пользователю (авторизированный пользователь)

.8         Добавление комментария объявлению (авторизированный пользователь)

3. Разработка проекта программного обеспечения

3.1       Анализ предметной области и разработка требований

.2         Разработка схемы ресурсов системы

.3         Разработка схемы работы системы

.4         Разработка проекта базы данных

.5         Разработка структуры классов

4. Разработка алгоритмов и их программная реализация

4.1       Алгоритм редактирования и удаления объявления

.2         Алгоритм редактирования и удаления питомца

.3         Алгоритм сохранения фотографий

.4         Алгоритм отображения списков диалогов

.5         Алгоритм подбора объявлений

. Тестирование программного средства

Заключение

Список использованных источников

Приложения А Код программы

Приложения Б Трассировочная таблица

Введение

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

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

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

Как и любое живое существо, собаки требуют к себе внимания и ухода. От различных аксессуаров (ошейники, поводки, гигиенические средства, корм) до лечения, дрессировки и выгула. Поиск подходящего партнера для вязки порой является непростым занятием.

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

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

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

1. Аналитический обзор и постановка задачи

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

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

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

Поэтому для сравнения блока объявлений разрабатываемой системы с частичными аналогами выделим ряд критериев оценки:

а)   визуализация объявлений карте;

б)      возможность подбора объявлений по специализированным для животных критериям (порода, вид и т.д.);

в)      возможность подбора объявлений по типу (спрос/предложение) и подробной категории (выгул, дрессура, косметические услуги и т.д.)

г)       возможность подбора объявлений по стоимости;

д)      возможность просмотра подробной информации об объявлении;

е)       возможность связи с владельцем объявления;

ж)      наличие отзывов и оценок;

з)       возможность сортировки объявлений по различным критериям (по рейтингу, стоимости услуг и т.п.).

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

а)   возможность создавать анкету пользователя с личной информацией;

б)      возможность создавать анкеты питомцев;

в)      возможность просмотра подробной информации о пользователе-владельце питомца;

г)       возможность связи с пользователем через отправку личных сообщений;

д)      организация поиска среди всех пользователей сайта;

е)       организация поиска среди всех питомцев сайта;

ж)      добавление других пользователей в друзья.

Для сравнения и анализа блока объявлений примем портал Cenotavr (#"896831.files/image001.jpg">

Рисунок 1 - Главная страница портала cenotavr.by

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

Рисунок 2 - Страница поиска объявления портала cenotavr.by

Petonik.com - это социальная сеть для владельцев животных, с небольшим блоком объявлений.

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

Объявления не являются центральным аспектом сайта, они реализованы в более общем виде без четкой разбивки по категориям. Для них предусмотрено лишь три рубрики: «Помогаем», «Нужен дом» и «Потеряшки». Соответственно, разместить объявление можно лишь в какой-то из этих рубрик. Фильтров и типа сортировки, кроме выбора региона (города), не предусмотрено. Карты для отображения объявлений также не предусмотрено. Поиск объявления не очень удобен.

Рисунок 3 - Страница личного профиля на сайте petonik.com

Рисунок 4 - Страница питомца на сайте petonik.com

Рисунок 5 - Страница поиска объявления на сайте petonik.com

В целом портал достаточно логичен. Функционала сайта достаточно, для создания анкеты и добавления питомцев. Для хорошей площадки объявлений не хватает четкой структуризации информации объявления и хорошей системы поиска и сортировки.

Портал Paws (#"896831.files/image006.jpg">

Рисунок 6 - Страница личного профиля на сайте paws.pro

Рисунок 7 - Страница питомца на сайте paws.pro

Таблица 1 - Сравнение показателей ресурсов cenotavr.by, petonik.com

Показатель для сравнения

cenotavr.by

petonik.com

1

визуализация объявлений карте

Отчасти (отображается выбранное объявление после перехода к подробной информации )

Нет

2

возможность подбора объявлений по специализированным для животных критериям (порода, вид и т.д.)

Да

Нет

3

возможность подбора объявлений по типу (спрос/предложение) и подробной категории (выгул, дрессура, косметические услуги и т.д.)

Да

Нет

4

возможность подбора объявлений по стоимости

Нет

Нет

5

возможность просмотра подробной информации об объявлении

Да

Да

6

возможность отбора объявлений по дополнительным параметрам

Нет

Нет

7

возможность связи с владельцем объявления

Да (для любого пользователя)

Да (только авторизированный пользователь)

8

наличие отзывов и оценок

Нет

Только комментарий

9

возможность сортировки объявлений по различным критериям (по цене, по дате, стоимости услуг и т.п.)

Нет

Нет


Таблица 2 - Сравнение показателей ресурсов paws.pro, petonik.com

Показатель для сравнения

paws.pro

petonik.com

 

1

возможность создавать анкету пользователя с личной информацией

Да

Только с указанием имени и города

 

2

возможность создавать анкеты питомцев

Да

Да

 

3

возможность просмотра подробной информации о пользователе-владельце питомца

Да

Да

 

4

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

Да

Да

 

5

организация поиска среди всех пользователей сайта

Да

Да

 

6

организация поиска среди всех питомцев сайта

Да (для любого пользователя)

Да (только авторизированный пользователь)

7

Добавление других пользователей в друзья

Да

Нет (только подписаться на новости)


Таким образом наиболее близким прототипом для блока объявлений является портал cenotavr.by, а для блока работы с личными данными и питомцами - портал paws.pro.

Исходя из вышеизложенного определим задачи разрабатываемого веб-приложения:

˗ визуализация объявлений на карте;

˗ возможность поиска объявления по категориям и разнообразным параметрам, задаваемым фильтрами (спрос/предложения, город, порода собаки, возможность выезда на дом, временные параметры (за день, неделю, месяц) и др. набор некоторых фильтров специфичен для категорий объявлений);

˗        возможность публикации отзыва к объявлению;

˗        возможность просмотра средней стоимости услуги по заданным параметрам (особенно актуально для при назначении стоимости услуги);

˗        возможность создания и публикации объявления, а также его редактирование и удаление;

˗        ведение рейтингов объявлений по отзывам и оценкам пользователей;

˗        возможность просмотра подробной информации объявления, профиля пользователя, страницы питомца;

˗        возможность обмена личными сообщениями.

2. Методы и модели, положенные в основу проекта

 

.1 Задание критериев отбора объявлений по фильтрам (любой пользователь, в том числе неавторизированный)


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

Диаграмма деятельности представлена на рисунке 8.

Рисунок 8 - Поиск объявлений

2.2 Редактирование личных данных (авторизированный пользователь)


Для редактирования личных данных пользователь должен осуществить вход в систему, затем перейти в раздел ‘Моя страница’ и нажать ссылку ‘Редактировать’ для перехода в режим редактирования личных данных. При входе система проверит введенные для авторизации данные и в случае обнаружения ошибок сообщит об этом пользователю.

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

Диаграмма деятельности представлена на рисунке 9.

Рисунок 9 - Редактирование личных данных

2.3 Редактирование объявления (авторизированный пользователь)

Для редактирования объявления пользователь должен осуществить вход в систему, затем перейти в раздел ‘Мои объявления’ и нажать ссылку ‘Редактировать’ для перехода в режим редактирования объявления. Далее, находясь в режиме редактирования объявления, пользователь вносит необходимые изменения а система проверяет их на наличие ошибок и в случае их обнаружения сообщает об этом пользователю. Внеся изменения, пользователь нажимает кнопку сохранить, для подтверждения сохранения изменений. Система в ответ производит необходимые изменения, и пользователь видит исправленную страницу объявления.

Диаграмма деятельности представлена на рисунке 10.

Рисунок 10 - Редактирование объявления


2.4 Редактирование питомца (авторизированный пользователь)

Для редактирования питомца пользователь должен осуществить вход в систему, затем перейти в раздел ‘Мои питомцы’ и нажать ссылку ‘Редактировать’ для перехода в режим редактирования питомца. Далее, находясь в режиме редактирования питомца, пользователь вносит необходимые изменения, а система проверяет их на наличие ошибок и в случае их обнаружения сообщает об этом пользователю. Внеся изменения, пользователь нажимает кнопку сохранить, для подтверждения сохранения изменений. Система в ответ производит необходимые изменения, и пользователь видит исправленную страницу питомца.

Диаграмма деятельности представлена на рисунке 11.

Рисунок 11 - Редактирование питомца


2.5 Создание нового объявления (авторизированный пользователь)

Для добавления объявления пользователь должен осуществить вход в систему, затем перейти в раздел ‘Мои объявления’ и нажать ссылку ‘Добавить’. Далее, находясь в режиме создания нового объявления, пользователь заполняет необходимые данные на форме, а система проверяет их на наличие ошибок и в случае их обнаружения сообщает об этом пользователю. Далее пользователь нажимает кнопку сохранить, для подтверждения создания нового объявления. Объявление сохраняется в системе, и пользователь видит новое объявление в списке объявлений.

Диаграмма деятельности представлена на рисунке 12.

Рисунок 12 - Создание нового объявления

2.6 Добавление нового питомца (авторизированный пользователь)

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

Диаграмма деятельности представлена на рисунке 13.

Рисунок 13 - Создание нового питомца

2.7 Отправка личного сообщения пользователю (авторизированный пользователь)

Для отправки сообщений другим пользователям необходимо осуществить вход в систему, затем перейти в раздел ‘Мои друзья’ выбрать пользователя из списка друзей и нажать ссылку ‘Отправить сообщение’. Далее пользователь набирает в поле текст сообщения и нажимает кнопку ‘Отправить’. Пользователь-отправитель видит новое сообщение в истории переписки, а пользователь-получатель получает уведомление о наличии непрочитанного сообщения.

Диаграмма деятельности представлена на рисунке 14.

Рисунок 14 - Отправка личного сообщения

2.8 Добавление комментария объявлению (авторизированный пользователь)


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

Диаграмма деятельности представлена на рисунке 15.

Рисунок 15 - Добавление комментария объявлению

3. Разработка проекта программного обеспечения

 

.1 Анализ предметной области и разработка требований


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

Поэтому необходимо предоставить для пользователей удобный и многофункциональный фильтр поиска, чтобы обеспечить наиболее простой способ подбора необходимой услуги и избавить пользователей от выискивания важной информации из текста объявлений. Объявления пользователей необходимо разбить на категории и выделить специфичные фильтры для каждой категории (например: при поиске объявлений о продаже собаки логично иметь фильтр для породы, для объявлений о выгуле логично иметь фильтр по местоположению в городе чтобы “сводить” владельцев по соседству, для косметических услуг фильтр для отбора объявлений по возможности выезда на дом, такой фильтр разумеется нелогичен для категории “продажа собак”). Также при реализации приложения следует для каждой категории объявлений выделить отдельно из общего текста объявления некоторые важные для этой категории объявлений атрибуты в отдельные поля чтобы помочь пользователю не упустить наиболее важную информацию при создании объявления и создавать ее в структурированном виде. Сам текст объявления в таком случае будет содержать по сути лишь дополнительное описание. Такой подход поможет организовать на сайте удобный и хорошо функциональный поиск объявлений.

Для обеспечения связи между пользователями должна быть организована возможность личной переписки, а также возможность оставлять комментарии под объявлением и выставление оценок. На основе оценок и отзывов должен быть организован рейтинг, который поможет пользователям в выборе.

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

В системе предполагается наличие нескольких типов пользователей.

Рисунок 16- Диаграмма основных пользователей системы

Для роли Admin должны быть предусмотрены некоторые дополнительные возможности работы с системой. Кроме того предусмотрен ограниченный набор функционала для неавторизированного пользователя.

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

Рисунок 17 - Диаграмма вариантов использования неавторизированного пользователя

Рисунок 18 - Диаграмма вариантов использования авторизированного пользователя (User)

Рисунок 19 - Диаграмма вариантов использования авторизированного пользователя (Admin)

Для достижения всех описанных выше целей, был сформирован следующий список требований к системе:

˗        система должна позволять регистрироваться на сайте и создавать личный кабинет;

˗        система должна предоставлять возможность редактирования, личных данных в личном кабинете пользователя;

˗ должна быть реализована возможность поиска объявления по категориям и разнообразным параметрам, задаваемым фильтрами (спрос/предложения, город, порода собаки, возможность выезда на дом, временные параметры (за день, неделю, месяц) и др. набор некоторых фильтров специфичен для категорий объявлений);

˗        должна быть реализована возможность просмотра подробной информации объявления, профиля пользователя, страницы питомца;

˗        должна быть реализована возможность публикации отзыва к объявлению;

˗        система должна позволять авторизированным пользователям обмениваться личными сообщениями;

˗        должна быть реализована возможность просмотра средней стоимости услуги по заданным параметрам (особенно актуально при размещении объявления для ориентации пользователя по ценовому вопросу);

˗        система должна позволять создавать и публиковать объявления, а также их редактирование и удаление;

˗        должен быть реализован расчет рейтингов объявлений по отзывам и оценкам пользователей.

Для пользователя Admin необходимо ко всему прочему предоставить следующий функционал:

˗ возможность правки и удаления комментариев;

˗        возможность удаления пользователей, питомцев и объявлений;

˗        возможность допуска объявления к публикации или ее блокирование.

 

.2 Разработка схемы ресурсов системы


Исходя из определенных требований к программному комплексу, можно перейти к разработке схемы ресурсов. Схемы ресурсов отображают конфигурацию блоков данных и обрабатывающих блоков. На чертеже РТДП 40324.034.001 представлена схема ресурсов разрабатываемой системы.

Схема ресурсов была построена на основании следующих правил обработки данных:

˗ система представляет собой веб-приложение asp.net, находящееся на веб-сервере, к которому клиент обращается посредством HTTP-запросов через интернет соединение;

˗        все пользовательские данные хранятся в таблицах базы данных;

˗        браузер формирует запрос и с помощью библиотеки ОС winsock.dll передает данные посредством протокола HTTP на веб-сервер;

˗        веб-сервер через интерфес internet Server API (ISAPI), находящийся в файле asp.net_isapi.dll передает запрос рабочему процессу;

˗        работа приложений .NET обеспечивается за счет наличия такого механизма как общеязыковая среда исполнения (Common Language Runtime, CLR) aspnet_wp.exe.

Для разработки системы был выбран шаблон MVC а именно ASP.NET MVC5. Язык программирования С#. Шаблон MVC разделяет работу веб-приложения на три отдельные функциональные роли: модель данных (model), пользовательский интерфейс (view) и управляющую логику (controller). Таким образом, изменения, вносимые в один из компонентов, оказывают минимально возможное воздействие на другие компоненты. Взаимодействия между контроллером, моделью и представлением показаны на рисунке 20:

Обработка основной части запросов выглядит следующим образом:

а) на сервер приходит запрос от пользователя;

б)      Сервер IIS запускает ASP.NET модуль, который будет запускать приложение на выполнение для обработки запроса;

в)      cистема маршрутизации ASP.NET определяет каким методом и в каком контроллере будет обработан запрос;

г)       выполняется нужный метод действия и упраление передается в представление View;

д)      движок представлений Razor рендерит View и отдаёт пользователю в виде Html и исполняемых скриптов.

В качестве хранилища данных для приложения используется созданная в MS-SQL Server база данных. База данных является реляционной, что означает использование связанных отношениями таблиц. Такая структура позволяет получить выигрыш в производительности за счет возможности объединения таблиц при запросах. Для доступа к данным в БД использована технология ADO.NET Entity Framework(EF). EF в сочетании с LINQ (Language-Integrated Query) представляет собой реализацию ORM для платформы .NET Framework от компании Microsoft. Entity Framework содержит механизмы создания и работы с сущностями базы данных через объектно-ориентированный код на языке, совместимым с CLR. LINQ представляет собой библиотеку, расширяющую возможности C#, и облегчающую создание запросов (благодаря LINQ можно создавать SQL-подобные запросы в коде C#).

Entity Framework является продолжением другого API-интерфейса для работы с базами данных в .NET - ADO.NET, в котором для работы с базами данных приходилось писать запросы на SQL и вставлять их в код.

В некоторых запросах к серверу используется технология ajax (обращение к серверу без перезагрузки страницы в браузере). Таким образом, разгружается канал передачи данных, а пользователь получает более дружественное поведение приложения, напоминающее desktop-приложения.

Для обеспечения требования к расширяемости и изменяемости приложения была выбрана многоуровневая архитектура. Разрабатываемое приложение разделено на три уровня.

Уровень представления. Это интерфейсный компонент, который представляет первый уровень, собственно приложение для конечного пользователя. Первый уровень не должен иметь прямых связей с базой данных (по требованиям безопасности), быть нагруженным основной бизнес-логикой (по требованиям масштабируемости) и хранить состояние приложения (по требованиям надежности).

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

Уровень данных. Хранит модели, описывающие используемые сущности, также здесь размещаются специфичные классы для работы с разными технологиями доступа к данным. В заданном приложении при использовании технологии EntityFramework это класс-наследник от DbContext, следящий за состоянием сущностей в памяти приложения и осуществляющий непосредственные запросы к БД MS SQL Server. Здесь также хранятся классы репозиториев через которые уровень бизнес-логики взаимодействует с базой данных.

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

 

.3 Разработка схемы работы системы


Схема работы системы представлена в графической части на чертеже РТДП-40324.034.002. Неавторизированный пользователь может просматривать объявления и пользоваться фильтром для поиска. При авторизации система проверяет, зарегистрирован ли пользователь с указанной парой логин-пароль в системе. Если в ходе авторизации возникла ошибка, система предлагает пользователю повторно ввести логин и пароль. При успешной авторизации пользователь попадает в личный кабинет, где может работать со своими личными данными, своими объявлениями, питомцами, также он может отправлять личные сообщения другим пользователям и оставлять отзывы чужим объявлениям.

Приложение состоит из нескольких блоков.

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

Блок регистрации в системе. Этот блок включает заполнение формы для регистрации в системе, включая логин, пароль, имя и фамилия, пол.

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

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

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

Блок работы с объявлениями пользователя. В этом блоке пользователь может создавать объявления, удалять и редактировать их, также он модет добавлять и удалять фотографии для объявления.

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

 

.4 Разработка проекта базы данных

 

По результатам анализа бизнес-логики выявлены информационные сущности, представленные в таблице 3.


Таблица 3 - Информационные сущности системы

Сущность

Описание сущности

1

Пользователь

Описывает пользователя системы и его права. Атрибутами являются: логин, пароль, его роль в системе

2

Профиль пользователя

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

3

Объявление

Описывает конкретное объявление, атрибуты: категория объявления, его название, текст, город и местоположение при необходимости, тип объявления (спрос/предложение), пол и порода питомца при необходимости, стоимость, средняя оценка по результатам отзывов, возможен ли выезд на дом (для некоторых категорий)

4

Категория объявления

Описывает категорию объявления, атрибуты: название категории

5

Питомец

Описывает конкретного питомца: кличка питомца, его порода, пол, дата рождения, возможность вязки, чип-номер при наличии, награды питомца, что любит, что не любит, описание питомца

6

Порода питомца

Описывает породу питомца, атрибуты: название породы, описание породы

7

Награда питомца

Описывает конкретную награду у питомца, атрибуты: название награды, питомец владелец награды

8

Сообщение

Описывает конкретное личное сообщение, атрибуты: дата и время отправки, тема, текст, пользователь-отправитель, пользователь-получатель, статус (просмотрено/не просмотрено)

9

Отзыв

Описывает конкретный отзыв к определенному объявлению, атрибуты: текст отзыва, оценка, дата и время написания отзыва, указание к какому объявлению относится отзыв


Кроме того выявлены нижеуказанные отношения между сущностями

Таблица 4 - Отношения между сущностями

Отношение

Описание отношения

1

Пользователь - профиль пользователя

Каждому пользователю соответствует 1 профиль, каждому профилю соответствует 1 пользователь. Это означает, что после регистрации в системе у пользователя автоматически создается одна страница профиля, где будет содержаться его личная информация

2

Профиль пользователя- питомец

Каждый пользователь может иметь от 0 до n питомцев, каждый питомец всегда имеет одного пользователя-владельца

3

Профиль пользователя- объявление

Каждый пользователь может иметь от 0 до n объявлений, каждое объявление всегда имеет одного пользователя-владельца

4

Профиль пользователя- сообщение

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

5

Объявление - отзыв

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

6

Питомец - награда

Каждый питомец может иметь от 0 до n наград, каждая награда принадлежит одному питомцу

7

Каждый пользователь может быть автором от 0 до n отзывов, каждое отзыв написан одним конкретным пользователем

8

Объявление - категория объявления

Каждое объявление принадлежит к определенной категории, каждая категория объявления может иметь от 0 до n объявлений в этой категории

9

Питомец - порода

Каждый питомец может относиться к 0 или 1 породе, каждая порода может относиться к 0..n питомцам

10

Объявление - порода

Каждое объявление может относиться к одной породе, каждая порода может относиться к 0..n объявлениям. Для некоторых объявлений может быть задана порода (порода актуальна, например для объявлениях о покупке/продаже питомцев)


На основании вышеизложенного была спроектирована БД. После этапа даталогического проектирования и нормализации до 4ой нормальной формы средствами ErWin 4.0 мы получаем следующую модель БД:

Рисунок 21 - Модель базы данных программной системы

В результате описание полученных таблиц имеет вид:

а) таблица Users (Пользователи), описывающая сущность пользователя, со следующими полями:

1) UserId int IDENTITY(1,1) NOT NULL, - первичный ключ;

2) RoleId int NOT NULL, - вторичный ключ;

3)      Email nvarchar(50) NOT NULL, -- логин для входя в систему;

4) Password nvarchar(50) NOT NULL, - пароль для входа в систему.

Таблица связана один-к-одному с таблицей Profiles;

б) таблица Roles (Роли):

1) RoleId    int IDENTITY(1,1) NOT NULL, - первичный ключ;

2)      Name                   nvarchar(50) NOT NULL, - название роли.

Таблица связана один-ко-многим с таблицей Users;

в) таблица Profiles (Профили):

1) UserId    int IDENTITY(1,1) NOT NULL, - первичный ключ;

2)      FirstName  nvarchar(50) NOT NULL - имя пользователя;

)        LastName nvarchar(50) NOT NULL - фамилия пользователя;

4)      Sex   bit NOT NULL - пол пользователя;

)        BirthDate   datetime NULL - дата рождения;

)        City nvarchar(50) NULL - город;

7)      Adress       nvarchar(50) NULL - адрес;

8)      PhoneNumber     nvarchar(50) NULL - номер телефона;

)        AvatarPath         nvarchar(50) NULL - путь к фото аватарки;

10) HaveImages    bit NOT NULL - имеет ли профиль фотографии.

Таблица связана отношением один-ко-многим с таблицей Pets, Advertizements, Users, Messages, Reviews.

г) таблица Advertizements (Объявления):

1) AdvertizementId        int IDENTITY(1,1) NOT NULL, - первичный ключ;

2)      Topic          nvarchar(50) NOT NULL, - название объявления;

3)      Text  nvarchar(max) NOT NULL, - текст объявления;

)        Price  float NULL - стоимость;

5)      IsDemand   bit NOT NULL - тип объявления(спрос/предложение);

6)      IsWithDeparture  bit NULL- выезд на дом (есть/нет);

7)      City   nvarchar(50) NULL, - город;

8)      Adress        nvarchar(50) NOT NULL, - адрес;

)        DateAndTime      datetime NOT NULL, - дата и время публикации;

10) UserId            int NOT NULL - вторичный ключ;

11)    DogBreedId         int NULL - вторичный ключ;

)        CategoryId           int NOT NULL - вторичный ключ;

)        Sex    bit NULL - пол питомца (при необходимости);

14)    Mark          float NULL - средняя оценка по отзывам;

15)    HaveImages         bit NOT NULL - есть ли фотографии.

Таблица связана отношением один-ко-многим с таблицей Reviews (Отзывы);

д) таблица Pets (Питомцы):

1) PetId int IDENTITY(1,1), - первичный ключ;

2)      Name nvarchar(50) NOT NULL, - кличка питомца;

)        Sex bit NOT NULL - пол;

)        BirthDate   datetime NULL - дата рождения;

)        Copulation bit NULL - возможность вязки (да/нет);

6)      Description nvarchar(max) NULL - описание питомца;

)        ChipNumber        nvarchar(50) NULL - чип-номер;

)        UserId                  int NOT NULL - вторичный ключ;

)        DogBreedId         int NULL - вторичный ключ;

10)  WhatLike     nvarchar(max) NULL - что любит;

11)    WhatDontLike     nvarchar(50) NULL - что не любит;

)        HaveImages         bit NOT NULL - есть ли фотографии.

Таблица связана отношением один-ко-многим с таблицей Rewards (Награды);

е) таблица Messages (Сообщения):

1) MessageId int IDENTITY(1,1), - первичный ключ;

2)      Topic nvarchar(50) NULL - тема сообщения;

3)      Text nvarchar(max) NOT NULL - текст сообщения;

)        DateAndTime      datetime NOT NULL - дата и время отправки;

)        WhoDeleted                  int NULL - Id пользователя, удалившего сообщение;

6)      ReceiverId            int NOT NULL - Id пользователя-получателя сообщений;

7)      AuthorId              int NOT NULL - вторичный ключ (Id пользователя-отправителя);

8)      HasBeenViewed  bit NULL - было ли сообщение просмотрено получателем;

ж) таблица Rewiews (Отзывы):

1) ReviewId          int IDENTITY (1,1) NOT NULL - первичный ключ;

2)      Text  nvarchar(max) NOT NULL - текст отзыва;

)        Mark int NULL - оценка отзыва;

)        DateAndTime               datetime NOT NULL - дата и время отправки;

)        AdvertizementId  int NOT NULL - вторичный ключ (Id объявления);

)        AuthorId    int NOT NULL - вторичный ключ (Id автора отзыва);

з) таблица Categories (Категории объявлений):

1) CategoryId       int IDENTITY(1,1) NOT NULL - первичный ключ;

2)      Name                   nvarchar(50) NOT NULL - название категории объявления;

и) таблица Rewards (Награды):

1) RewardId int IDENTITY(1,1) NOT NULL, - первичный ключ;

2)      RewardText nvarchar(max) NOT NULL, - описание награды;

)        PetId           int NOT NULL - вторичный ключ (питомец-обладатель награды);

к) таблица DogBreads (Породы):

1) DogBreedId     int IDENTITY(1,1) NOT NULL, - первичный ключ;

2)      Name         nvarchar(50) NOT NULL, - название;

3)      Description         nvarchar(max) NULL - описание.

Таблица связана отношением один-ко-многим с таблицами Advertizements и Pets.

 

.5 Разработка структуры классов


На рисунке 22 отображена итоговая структура классов предметной области программной системы:

Рисунок 22 - Диаграмма классов программной системы

4. Разработка алгоритмов и их программная реализация

 

.1 Алгоритм редактирования и удаления данных объявления


Алгоритм редактирования и удаления данных объявления представлен на рисунке 23. Если выбрана операция удаления, программа извлекает из данных формы идентификационный номер удаляемого объявления вместе с другой полезной информацией, такой как идентификационный номер автора объявления. Этот идентификационный номер используется приложением для ограничения прав на удаление так, чтобы только авторизированный пользователь с таким номером мог произвести удаление. Поскольку удаление данных, это непосредственная операция по изменению состояния приложения, то запросы Get являются нежелательными для подобных действий. Это связано с тем, что в этом случае удаление можно произвести просто перейдя по ссылке, что небезопасно. Потому в данном конкретном случае используется запрос типа Post. При удалении объявления проверяется, есть ли в таблице “Rewievs” записи, связанные с этим объявлением. Если имеются, то программа удаляет записи из этой таблицы и только затем удаляет данные объявления.

При выборе операции редактирования объявления (нажали ссылку «Редактировать»), сервер в ответ формирует страницу с формой редактирования данных, заполненную данными выбранного объявления. После того как пользователь внес необходимые изменения, он нажимает кнопку «Сохранить» для подтверждения сохранения изменений. Тогда система проверяет, корректны ли введённые данные и в случае обнаружения ошибки выдаёт сообщения, поясняющие суть ошибок. Если данные корректны, система производит сохранение изменений в БД. Кроме того, в случае, если к самому объявлению на форме были добавлены фотографии, то система проверяет их на корректность формата и на непустое значение и далее присваивает этим файлам уникальные имена и сохраняет их в файловой системе сервера. Детализация алгоритма сохранения фотографии приведена далее.

При выборе операции добавления нового объявления (нажали ссылку «Добавить»), сервер в ответ формирует страницу с формой добавления нового объявления. После того как пользователь заполнил форму, он нажимает кнопку «Сохранить» для подтверждения сохранения объявления. Тогда система проверяет, корректны ли введённые данные и в случае обнаружения ошибки выдаёт сообщения, поясняющие суть ошибок. Если данные корректны, система производит сохранение нового объявления в БД. Кроме того, в случае, если к самому объявлению на форме были добавлены фотографии, то система проверяет их на корректность формата и на непустое значение и далее присваивает этим файлам уникальные имена и сохраняет их в файловой системе сервера. Детализация алгоритма сохранения фотографии приведена далее.

При нажатии на кнопку “Добавить”, программа извлекает из строки запроса идентификационный номер объявления и формирует страницу с формой для нового объявления. После того как пользователь заполнил формы и нажал кнопку «Сохранить», система проверяет, корректны ли введённые данные. Если ошибок не обнаружено, новое объявление сохраняется в БД, в случае наличия ошибок во введенных данных отображаются соответствующие сообщения. Если к самому объявлению на форме были добавлены фотографии, то система проверяет их на корректность формата и на непустое значение и далее присваивает этим файлам уникальные имена и сохраняет их в файловой системе сервера.

Рисунок 23 - Алгоритм редактирования и удаления объявления

4.2 Алгоритм редактирования и удаления данных питомца


Алгоритм редактирования и удаления данных питомца представлен на рисунке 24. Он аналогичен предыдущему алгоритму, с тем лишь отличием, что на форме имеется возможность добавлять питомцу награды. В соответствии с этим при редактировании и при добавлении нового питомца происходит проверка наличия на форме наград, если они обнаружены, то происходит их сохранение в БД. При удалении питомца также проверяется наличие у него записей о наградах (записей в таблице Rewards), если они обнаружены, то вместе с удалением питомца происходит и удаление этих записей.

Аналогично предыдущему алгоритму при заполнении формы система проверяет ее на наличие ошибок. Также производится проверка на наличие фоторгафий и их сохранение в файловой системе, как это описано в предыдущем алгоритме.

Рисунок 24 - Алгоритм редактирования и удаления данных питомца

4.3 Алгоритм сохранения фотографий


Алгоритм сохранения фотографий представлен на рисунке 25.

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

Фотографии могут принадлежать одной из трех сущностей (пользователь, питомец, объявление). По этой причине фотографии для определенного пользователя сохраняются по пути ‘~/ProfilePhotos/[ID-номер пользователя]’, фотографии для определенного питомца по пути ‘~/PetPhotos/[ID-номер питомца]’, фотографии для определенного объявления по пути ‘~/AdvPhotos/[ID-номер объявления]’. В разных местах сайта необходимо отображать одну и ту же фотографию но различного размера. Например, для отображения списка объявлений рядом с каждым объявлением будет маленькая фотография-иконка, для отображения подробной информации об объявлении более крупная, а в случае просмотра фотографий объявления еще более крупная.

С целью оптимизации передачи данных по сети интернет от сервера клиенту было принято решение создавать три версии фотографии разного расширения и размера с приставками соответственно big’ ‘small’ ‘tiny. Для обеспечения уникального имени файла в пределах директории обрабатываемой сущности используется следующая схема именования: приставка+порядковый_номер. Например, файл будет существовать в трех версиях в виде big1.jpg, small1.jpg, tiny1.jpg. После определения директории для сохранения, система присваивает переменной nextNum максимальный номер в названии уже сохраненных на сервере файлов для обрабатываемой сущности. Далее в цикле осуществляется проход по коллекции отправленных клиентом файлов. Если файл корректный, то формируются правила его сохранения в трех версиях, включая шаблон именования приставка+ nextNum. Потом в цикле сохраняются эти три версии по определенной ранее директории. Если такой директории нет, то она создается. В конце итерации счетчик nextNum увеличивается на единицу.

Рисунок 25 - Алгоритм сохранения фотографий

4.4 Алгоритм отображения списков диалогов


Алгоритм отображения списков диалогов пользователя представлен на рисунке 27. В приложении реализована возможность пользователей обмениваться личными сообщениями. У каждого пользователя есть список его диалогов (диалог здесь понимается как перечень сообщений, в котором данный пользователь выступает в качестве одного участника, а другим участником выступает другой конкретный пользователь). Все сообщения пользователей хранятся в одной таблице в БД.

Приведенный алгоритм отображает логику формирования списка диалогов пользователя, каждый элемент которого представляет собой последнее сообщение в истории переписки и пометки пользователя, с которым ведется переписка. Для формирования такого списка сначала из БД извлекается коллекция messages из последних сообщений в каждом диалоге. Далее полученная коллекция отсортировывается по времени. После в цикле осуществляется проход по этой коллекции. В каждой итерации цикла проверяется, является ли авторизированный польователь автором текущего сообщения цикла mes. Если да, то переменной author присваивается значение ‘Вы’. В противном случае значение для этой переменной формируется из объекта mes как author=mes.Author.FirstName+mes.Author.LastName. Если авторизированный пользователь не является автором сообщения и mes имеет пометку ‘непрочитанное’, то переменной darkBackGround присваивается true, чтобы сделать фон для данного диалога затемненным при отображении на странице. В противном случае darkBackGround=false.

Кроме того при отображении диалога имеет смысл показывать информацию о пользователе, с которым авторизированный пользователь ведет переписку. Для хранения этой информации служит переменная usrToShow. Она получает значение mes.Receiver, если автор сообщения это авторизированный пользователь и значение mes.Author в противоположном случае. Далее в итерации переменной unViewed присваивается количество сообщений из БД, помеченных как непрочитанные и у которых получатель это зарегистрированный пользователь, а отправитель это пользователь usrToShow. Вся эта информация необходима для отображения информации о диалоге пользователя включая сам текст сообщения, информация о собеседник и количество непрочитанных авторизированным пользователем сообщений в этом диалоге. Пояснение по внешнему виду списка диалогов приведено на рисунке 26.

Рисунок 26 - Внешний вид списка диалогов пользователя

Рисунок 27 - Алгоритм отображения списков диалогов

 

.5 Алгоритм подбора объявлений


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

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

Рисунок 28 - Алгоритм подбора объявлений



5. Тестирование программного средства

 

Тестирование программного обеспечения - проверка соответствия между реальным и ожидаемым поведением программы, осуществляемая на конечном наборе тестов, выбранном определенным образом. В более широком смысле, тестирование - это одна из техник контроля качества, включающая в себя активности по планированию работ (Test Management), проектированию тестов (Test Design), выполнению тестирования (Test Execution) и анализу полученных результатов (Test Analysis).Все методы тестирования можно условно разделить на две группы: тестирование по методу белого ящика и тестирование по методу черного ящика.

Разность этих подходов заключается в наличии доступа к исходному коду тестируемого ПО. Как можно догадаться из названий методов - при использовании «черного ящика» тестировщик использует только внешние рычаги взаимодействия с программой: с помощью пользовательского интерфейса или подключившись к тестируемой системе. При работе с «белым ящиком» тестировщик имеет доступ к коду, тем самым тестируя внутреннюю структуру программы.

Любое приложение необходимо тестировать. Качественное тестирование позволяет обнаружить ошибки и недочеты в работе программы на ранних этапах ее жизненного цикла, когда стоимость их исправления гораздо ниже, чем если бы приложение уже использовалось в работе пользователей. cenotavr petonik объявление животное

Для тестирования приложения был выбран метод черного ящика, тестирование производилось вручную. Был разработан набор smoke-тестов, призванных поверхностно проверить работоспособность системы, и набор criticalpath-тестов (функциональных тестов), целью которых является проверить работоспособность основного функционала приложения и его соответствие требованиям системы. Наборы тестов приведены ниже.

Разработаны 3 smoke-теста, которые предназначены для проверки общей работоспособности системы. Разработанные тесты описаны в таблице 5.

Таблица 5 -Smoke тесты

ID

Модуль

Подмодуль

Описание теста

Ожидаемый результат

SM_T_1

Веб-риложение

HomePage

Запуск приложения: 1.Ввести адрес в адресную строку браузера

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

SM_T_2

Веб-риложение

Authorization

Вход в систему с корректными данными: 1.Ввести логин ‘jenik90@tut.by’ и пароль ‘111111’ 2.Нажать кнопку ‘Войти’

1.Отобразится главная страница профиля в личном кабинете пользователя

SM_T_3

Веб-риложение

Authorization

Вход с некорректными данными: 1.Ввести логин ‘notexist@tut.by’ и пароль ‘111111’ 2.Нажать кнопку ‘Войти’

1.Поля формы заполнены введёнными данными. 2.Отображается сообщение о том, что логин или пароль введён неверно

 

Также разработан набор функциональных тестов. Разработанные тесты приведены в таблице 6.



Таблица 6 - Функциональные тесты

Иденти-фикатор

Модуль

Подмодуль/экран

Описание теста

Ожидаемый результат

CP-Т_1

веб-приложение

Search

Поиск объявления по фильтрам, задать значения основным фильтрам 1.Перейти на домашнюю страницу 2.Выбрать категорию объявления 3.Выбрать город 4.Выбрать период для отображения 5.Задать на слайдере диапозон стоимости

1.Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Отображается первая страница списка объявлений выбранной категории, на карте отображаются все объявления для данной категории, где задан атрибут адреса 3. Отображается первая страница списка объявлений для выбранной категории и данного города, на карте отображаются все подходящие элементы, где задан атрибут адреса 4.Отображается первая страница списка объявлений для выбранной категории, выбранного города соответствующих указанному периоду, на карте отображаются все подходящие элементы, где задан атрибут адреса 5. Отображается первая страница списка объявлений для выбранной категории, выбранного города соответствующих указанному периоду и диапозону цен, на карте отображаются все подходящие элементы, где задан атрибут адреса фильтрам возле заданного адреса

CP-Т_2

веб-приложение

Search

Поиск объявления по фильтрам, задать значения основным и дополнительным фильтрам 1.Перейти на домашнюю страницу 2.Выбрать категорию объявления ‘Продажа собак’ 3.Выбрать город 4.Выбрать период для отображения 5.Задать на слайдере диапозон стоимости 6. Нажать кнопку ‘Дополнительно’ внизу блока фильтров 7. Выбрать породу из списка пород в появившемся блоке дополнительных параметров поиска 8.Выбрать пол в появившемся блоке дополнительных параметров

1.Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Отображается первая страница списка объявлений выбранной категории, на карте отображаются все объявления для данной категории, где задан атрибут адреса 3. Отображается первая страница списка объявлений для выбранной категории и данного города, на карте отображаются все подходящие элементы, где задан атрибут адреса 4.Отображается первая страница списка объявлений для выбранной категории, выбранного города соответствующих указанному периоду, на карте отображаются все подходящие элементы, где задан атрибут адреса 5. Отображается первая страница списка объявлений для выбранной категории, выбранного города соответствующих указанному периоду и диапозону цен, на карте отображаются все подходящие элементы, где задан атрибут адреса фильтрам возле заданного адреса 6.Отображается блок дополнительных параметров поиска (по породе и полу) 7.Отображается первая страница объявлений, соответствующих всем предыдущим фильтрам а также выбранной породе, на карте отображаются все подходящие элементы, где задан атрибут адреса 8.Отображается первая страница объявлений, соответствующих всем предыдущим фильтрам а также выбранной породе и заданному полу, на карте отображаются все подходящие элементы, где задан атрибут адреса

CP-Т_3

веб-приложение

Search

Проверка меток на карте 1.Перейти на домашнюю страницу 2.Задать произвольные значения фильтрам поиска 3.Кликнуть по любой метке на карте 4.Кликнуть кнопке ‘Подробнее’ у всплывшего возле метки краткого описания объявления

1.Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Отображается первая страница списка объявлений, подходящих заданным фильтрам, на карте отображаются все подходящие объявления, где задан атрибут адреса 3. Возле метки появляется блок с краткой информацией по объявлению 4.Отображается страница с подробной информацией по выбранному объявлению

CP-Т_4

веб-приложение

Sorting

Проверка сортировки результатов 1.Перейти на домашнюю страницу 2.Задать произвольные значения фильтрам поиска 3.Под блоком карты рядом с полем ‘сортировать по’ выбрать из списка значение ‘дате начать со старых’ 4.Под блоком карты рядом с полем ‘сортировать по’ выбрать из списка значение ‘цене начать с дешевых’ 5.Под блоком карты рядом с полем ‘сортировать по’ выбрать из списка значение ‘цене начать с дорогих’ 6.Под блоком карты рядом с полем ‘сортировать по’ выбрать из списка значение ‘рейтингу’

1.Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Отображается первая страница списка объявлений, подходящих заданным фильтрам, на карте отображаются все подходящие объявления, где задан атрибут адреса 3. Отображается первая страница списка объявлений, подходящих заданным фильтрам и отсортированных по возрастанию по дате, на карте изменений не происходит 4. Отображается первая страница списка объявлений, подходящих заданным фильтрам и отсортированных по возрастанию по цене, на карте изменений не происходит 5. Отображается первая страница списка объявлений, подходящих заданным фильтрам и отсортированных по убыванию по цене, на карте изменений не происходит 6. Отображается первая страница списка объявлений, подходящих заданным фильтрам и отсортированных по убыванию по рейтингу, на карте изменений не происходит

CP-Т_5

веб-приложение

Authorization

Вход в личный кабинет 1.Перейти на домашнюю страницу 2.В блоке входа в личный кабинет нажать кнопку ‘Войти’ 3.В блоке входа в поле ‘email’ввести существующий логин 4.В блоке входа в поле ‘пароль’ ввести неверный пароль 5.Нажать кнопку ‘Войти’ 6.В блоке входа в поля ‘email’ и ‘пароль’ ввести корректные значения для логина и пароля и нажать кнопку ‘Войти’

1. Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Возле поля ‘email’ появляется сообщение о необходимости указания emaila, возле поля ‘пароль’ появляется сообщение о необходимости указания пароля 3.Возле поля ‘email’ сообщение об ошибке исчезает 4.Возле поля ‘пароль’ сообщение об ошибке исчезает 5.В блоке входа появляется сообщение о неверном пароле 6.Отображается главная страница профиля личного кабинета

CP-Т_6

веб-приложение

Аccount

Регистрация пользователя 1.Перейти на домашнюю страницу 2.Нажать на меню Регистрация 3.Ввести в поле’ e-mail’ лат. буквами значение по шаблону *@*.* 4.Ввести поле ‘Пароль’ лат. значение не менее 6 знаков 5.Ввести в поле ‘подтвердите пароль’ тот же пароль 6.Заполнить поля ‘Имя’ и ‘Фамилия’ буквенными значениями не менее 2-х символов 7.Выбрать пол, поставить чекбокс о согласии с условиями сайта 8.Нажать кнопку ‘Зарегистрироваться’

1. Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления 2.Отображается страница с формой для регистрации пользователя 3.Отображается введенный email в поле email 4. В поле пароль отобразятся точки вместо вводимых символов 5. В поле ‘Подтвердите пароль’ отобразятся точки вместо вводимых символов 6. Поля ‘Имя’ и ‘Фамилия’ заполнятся ответствующими значениями 7.Радиокнопка отобразится возле соответствующего значения пола, чекбокс пометится как отмеченный 8.Произойдет регистрация нового пользователя в системе и отобразится главная страница профиля зарегистрированного пользователя

CP-Т_7

веб-приложение

Аccount

Редактирование личных данных пользователя 1.Войти в существующий личный кабинет на сайте 2.Нажать кнопку ‘Редактировать’ под фотографией-аватаркой на главной странице профиля 3.Заполнить поля в отобразившейся форме новыми корректными значениями 4.Нажать кнопку ‘Выбрать файл’ для загрузки фотографии 5.В появившемся диалоговом окне выбрать файл фотографии и нажать кнопку ‘Открыть’ 6.Нажать кнопку ‘Сохранить’

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится форма для редактирования личных данных со старыми значениями в полях для заполнения 3.В полях для заполнения появляются новые значения 4.Отобразится диалоговое окно для загрузки фотографии 5.На странице рядом с кнопкой ‘Выберите файл’ появляется изображение выбранной в диалоговом окне фотографии, также рядом с кнопкой отображается имя загружаемого файла 6.Отображается главная страница профиля в личном кабинете пользователя с новыми значениями данных, в слайдере фотографий появляется новая загруженная фотография

CP-Т_8

веб-приложение

Аccount

Добавление питомца в личном кабинете 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои питомцы’ в левой боковой навигационной панели 3.Нажать ссылку ‘Создать питомца’ в конце списка питомцев 4.Заполнить появившуюся форму корректными данными о питомце 5.Нажать ссылку ‘Добавить’ возле метки ‘Награды’ на форме 6.Заполнить появившееся поле информацией о награде 7.Повторить пункты 4-5 для создания у питомица списка наград 8.Нажать кнопку ‘Выбрать файл’ для загрузки фотографии 9.В появившемся диалоговом окне выбрать файл фотографии и нажать кнопку ‘Открыть’ 10.Нажать кнопку ‘Добавить фото’ 11.Повторить пункты 8-10 несколько раз для подготовки нескольких фотографий для загрузки на сервер 12.Нажать кнопку ‘Сохранить’

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится списокпитомцев пользователя с краткой информацией по каждому из них 3.Отобразится форма для добавления нового питомца с пустыми полями 4.Поля заполняются введенными данными 5.Появиться поле для информации о награде 6.В появившемся поле отображается введенная информация 7.В блоке ‘Награды’ появляется группа заполненных полей о наградах питомца 8.Отобразится диалоговое окно для загрузки фотографии 9.На странице рядом с кнопкой ‘Выберите файл’ появляется изображение выбранной в диалоговом окне фотографии, также рядом с кнопкой отображается имя загружаемого файла 10.Появляется дополнительный блок для загрузки фотографии 11. В блоке ‘Фотографии’ появляется группа выбранных для загрузки на сервер фотографий питомца 12.Отображается страница с подробной информацией о созданном питомце, на слайдере появляются загруженные фотографии

CP-Т_9

веб-приложение

Account

Добавление объявления в личном кабинете 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои объявления’ в левой боковой навигационной панели 3.Нажать ссылку ‘Добавить объявление’ в конце списка объявлений 4.Заполнить появившуюся форму корректными данными о новом объявлении 5.Нажать кнопку ‘Выбрать файл’ для загрузки фотографии 6.В появившемся диалоговом окне выбрать файл фотографии и нажать кнопку ‘Открыть’ 7.Нажать кнопку ‘Добавить фото’ 8.Повторить пункты 8-10 несколько раз для подготовки нескольких фотографий для загрузки на сервер 9.Нажать кнопку ‘Сохранить’

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список объявлений пользователя с краткой информацией по каждому из них 3.Отобразится форма для добавления нового объявления с незаполненными полями 4.Поля формы заполняются введенными данными 5.Отобразится диалоговое окно для загрузки фотографии 6.На странице рядом с кнопкой ‘Выберите файл’ появляется изображение выбранной в диалоговом окне фотографии, также рядом с кнопкой отображается имя загружаемого файла 7.Появляется дополнительный блок для загрузки фотографии 8.В блоке ‘Фотографии’ появляется группа выбранных для загрузки на сервер фотографий для объявления 9.Отображается страница с подробной информацией о созданном объявлении, на слайдере появляются загруженные фотографии

CP-Т_10

веб-приложение

Messages

Отправка личного сообщения пользователю 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои друзья’ в левой боковой навигационной панели 3.В отобразившемся списке пользователей нажать ссылку подробнее возле интересующего пользователя 4.Нажать кнопку ‘Отправить сообщение’ под фотографией пользователя 5.Заполнить поле для текста сообщения и нажать кнопку ‘Отправить’ 6.Нажать ссылку ‘Выйти’ в блоке заголовка сайта 7.Ввести логин и пароль пользователя, которому было отправлено сообщение и нажать кнопку ‘Войти’ 8.Нажать ссылку ‘Мои сообщения’ в левой боковой навигационной панели 9.В отобразившемся списке диалогов нажать на диалог, где отправитель это предыдущий авторизированный пользователь

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список друзей пользователя с краткой информацией по каждому из них 3.Отобразится страница с подробной информацией о выбранном пользователе 4.Отобразится страница с историей переписки с данным пользователем и форма для отправки нового сообщения, состоящая из одного поля 5.Поле заполнится введенными данными и после нажатия ‘Отправить’ появится как последнее сообщение в истории переписки, при этом поле для ввода сообщения станет пустым 6.Отобразится домашняя страница формой для входя в личный кабинет и ссылкой на регистрацию в левой боковой панели 7. Отобразится главная страница профиля в личном кабинете пользователя, возле ссылки ‘Мои сообщения отображена пометка с количеством непрочитанных сообщений’ 8.Отображается список диалогов пользователя, отсортированный по убывания по времени, в каждом диалоге отображено последнее сообщение (или его начало, если сообщение длинное) в истории переписки, диалог с предыдущим авторизированным пользователем подсвечен затемненным фонов и имеет пометку с количеством непрочитанных в этом диалоге сообщений 9. Отображается история переписки с последним с предыдущим авторизированным пользователем, последнее сообщение в истории это сообщение отправленное на предыдущем этапе теста. Рядом со ссылкой ‘Мои сообщения’ пометка количества непрочитанных сообщение уменьшается на число сообщение, которые были только что просмотрены в данном диалоге

CP-Т_11

веб-приложение

Messages

Проверка уведомления о пришедшем сообщении вне режима работы с диалогом Для реализации теста необходима работа на двух компьютерах одновременно под двумя разными аккаунтами на сайте В ПЕРВОМ АККАУНТЕ : . 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои друзья’ в левой боковой навигационной панели 3.В отобразившемся списке пользователей нажать ссылку подробнее возле пользователя обладателя второго аккаунта в тесте 4.Нажать кнопку ‘Отправить сообщение’ под фотографией пользователя ВО ВТОРОМ АККАУНТЕ : . 5.Войти в личный кабинет на сайте В ПЕРВОМ АККАУНТЕ : 6.Заполнить поле для текста сообщения и нажать кнопку ‘Отправить’

В ПЕРВОМ АККАУНТЕ : . 1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список друзей пользователя с краткой информацией по каждому из них 3.Отобразится страница с подробной информацией о выбранном пользователе 4.Отобразится страница с историей переписки с данным пользователем и форма для отправки нового сообщения, состоящая из одного поля ВО ВТОРОМ АККАУНТЕ : 5. Отобразится главная страница профиля в личном кабинете пользователя 6. В ПЕРВОМ АККАУНТЕ : . Поле заполнится введенными данными и после нажатия ‘Отправить’ появится как последнее сообщение в истории переписки, при этом поле для ввода сообщения станет пустым ВО ВТОРОМ АККАУНТЕ : . Возле ссылки ‘Мои сообщения пометка с количеством непрочитанных сообщений’увеличивается на 1, а в случае отсутствия ранее непрочитанных сообщений становится равной ‘(+1)’, кроме того срабатывает звуковой сигнал, оповещающий о пришедшем сообщении

CP-Т_12

веб-приложение

Messages

Проверка уведомления о пришедшем сообщении в режиме работы с диалогом Для реализации теста необходима работа на двух компьютерах одновременно под двумя разными аккаунтами на сайте В ПЕРВОМ АККАУНТЕ : . 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои друзья’ в левой боковой навигационной панели 3.В отобразившемся списке пользователей нажать ссылку подробнее возле пользователя обладателя второго аккаунта в тесте 4.Нажать кнопку ‘Отправить сообщение’ под фотографией пользователя ВО ВТОРОМ АККАУНТЕ : . 5.Войти в личный кабинет на сайте 6. Нажать ссылку ‘Мои диалоги’ в левой боковой навигационной панели 7. В списке диалогов выбрать диалог-переписку с пользователем обладателем первого аккаунта В ПЕРВОМ АККАУНТЕ: 8.Заполнить поле для текста сообщения и нажать кнопку ‘Отправить’

В ПЕРВОМ АККАУНТЕ : . 1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список друзей пользователя с краткой информацией по каждому из них 3.Отобразится страница с подробной информацией о выбранном пользователе 4.Отобразится страница с историей переписки с данным пользователем и форма для отправки нового сообщения, состоящая из одного поля ВО ВТОРОМ АККАУНТЕ : 5. Отобразится главная страница профиля в личном кабинете пользователя 6. Отобразится список диалогов пользователя 7. Отображается история переписки второго и первого полоьзователя 8. В ПЕРВОМ АККАУНТЕ : . Поле заполнится введенными данными и после нажатия ‘Отправить’ появится как последнее сообщение в истории переписки, при этом поле для ввода сообщения станет пустым ВО ВТОРОМ АККАУНТЕ : . срабатывает звуковой сигнал, оповещающий о пришедшем сообщении, в истории переписки появляется отправленное первым пользователем сообщение

CP-Т_13

веб-приложение

Profile

Проверка удаления объявления пользователем 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои объявления’ в левой боковой навигационной панели 3.Нажать кнопку ‘Подробнее’ рядом с интересующим из списка объявлением 4.В открывшемся окне нажать кнопку ‘Удалить’ 5.В появившемся диалоговом окне нажать кнопку ‘Отмена’ 6.Повторить пункт 4 7.В появившемся диалоговом окне нажать кнопку ‘ОК’

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список объявлений пользователя с краткой информацией по каждому из них 3.Отобразится страница с подробной информацией о выбранном объявлении 4.Отобразится диалоговое окно о подтверждении удаления 5. Отобразится страница с подробной информацией об объявлении, удаление произведено не будет 6. Отобразится диалоговое окно о подтверждении удаления 7.Отобразится список объявлений пользователя без удаленного объявления

CP-Т_14

веб-приложение

Profile

Проверка удаления питомца пользователем 1.Войти в личный кабинет на сайте 2.Нажать ссылку ‘Мои питомцы’ в левой боковой навигационной панели 3.Нажать кнопку ‘Подробнее’ рядом с интересующим из списка питомцем 4.В открывшемся окне нажать кнопку ‘Удалить’ 5.В появившемся диалоговом окне нажать кнопку ‘Отмена’ 6.Повторить пункт 4 7.В появившемся диалоговом окне нажать кнопку ‘ОК’

1.Отобразится главная страница профиля в личном кабинете пользователя 2.Отобразится список питомцев пользователя с краткой информацией по каждому из них 3.Отобразится страница с подробной информацией о выбранном питомце 4.Отобразится диалоговое окно о подтверждении удаления 5. Отобразится страница с подробной информацией о питомце, удаление произведено не будет 6. Отобразится диалоговое окно о подтверждении удаления 7.Отобразится список питомцев пользователя без удаленного объявления

CP-Т_15

веб-приложение

Sorting

Проверка страничной пагинации 1.Перейти на домашнюю страницу 2.Задать произвольные значения фильтрам поиска 3.Нажать внизу страницы ссылку на 2-ую страницу 4.Нажать внизу страницы ссылку на 4-ую страницу 5.Нажать внизу страницы ссылку на последнюю страницу 6.Нажать внизу страницы ссылку на 1-ую страницу

1.Отображается домашняя страница с картой и боковой панелью поиска и первой страницей списка объявлений по умолчанию, на карте отображаются все объявления, внизу страницы ссылка на первую страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый) 2.Отображается первая страница списка объявлений, подходящих заданным фильтрам, на карте отображаются все подходящие объявления, где задан атрибут адреса , внизу страницы ссылка на первую страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый) 3. Отображается вторая страница списка объявлений, подходящих заданным фильтрам, на карте изменений не происходит, внизу страницы ссылка на вторую страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый) 4. Отображается четвертая страница списка объявлений, подходящих заданным фильтрам, на карте изменений не происходит, внизу страницы ссылка на 4-ую страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый) 5. Отображается последняя страница списка объявлений, подходящих заданным фильтрам, на карте изменений не происходит, внизу страницы ссылка на последнюю страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый) 6. Вновь отображается первая страница списка объявлений, подходящих заданным фильтрам, на карте изменений не происходит, внизу страницы ссылка на первую страницу будет подсвечена синим фоном и будет недоступна для нажатия, ссылки на остальные страницы будут иметь фон по умолчанию (белый)



Указанный набор тестов был составлен на основании требований к системе. Тестовые сценарии были разработаны для проверки работы конкретного функционала, необходимость реализации которого была определена в спецификации требований. Приведенные выше тесты были успешно выполнены, выявленные в ходе выполнения тестов ошибки были устранены. В результате программная система успешно прошла этап тестирования и соответствует спецификации требований.

Заключение

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

Был произведен глубокий анализ предметной области, разработана спецификация требований к системе, выявлены бизнес-акторы и их функции. Были определены основные варианты использования системы в рамках действий бизнес-акторов и выявлен основной функционал приложения для его реализации. Полученное в результате приложение позволяет пользователям создавать на сайте личный кабинет, в котором предоставляется возможность создавать страницы своим питомцам а также публиковать объявления в различных рубриках. Реализована возможность оставлять отзывы объявлениям, а также возможность обмена личными сообщениями.

Полученное в итоге приложение имеет многоуровневую архитектуру (модель представления, модель бизнес-логики, модель данных). Каждый уровень является изолированным и мало связан логически с другими уровнями. Связь уровней осуществляется через реализацию интерфейсов, что позволяет легко модифицировать приложение, вносить изменение и заменять некоторые модули программы на другие без серьезных проблем с перестроением приложения и рефакторингом. Так например можно легко заменить модель данных, используя в качестве хранилища не БД а XML-файл или CSV-файл. Для этого лишь надо реализовать несколько публичных интерфейсов, избегая при этом масштабного рефакторинга кода.

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

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

В ходе работы над проектом были приобретены практические навыки использования таких технологий как ASP.NET MVC5, JQuery, JavaScript. Также были изучены основы работы с Entity Framework 6, Ajax, DI (Dependency Injection), Html и CSS. Кроме того в проекте использовалось сторонний API (Yandex maps) и были получены навыки работы с ним. Также использовались некоторые специфичные библиотеки JavaScript (слайдер фотографий, слайдер для диапозона цен, диалоговые окна).

Список использованных источников

1.        Фримен, А. ASP.NET MVC 4 с примерами на C# 5.0 для профессионалов. 4-е изд. - Россия : Вильямс, 2013. - 688 с.

2.      Фримен, А. JQuery для профессионалов- Москва-Питер-Киев: Вильямс, 2013. - 953 с.

.        Нейгел, К. C#5.0 и платформа .NET 4.5 для профессионалов-СПб: Москва-Питер-Киев: Вильямс, 2014. - 1435 с.

.        Рихтер, Д. CLR via C#. Программирование на платформе Microsoft .NET Framework 4.5 на языке C#. - СпБ. : Питер, 2013. - 896 с

.        Дейт Дж. Кристофер Введение в системы баз данных. - М.: дом "Вильяме", 2005. - 8-е издание 1328 с.

.        Герберт Шилдт. C# 4.0: полное руководство - М.: «Вильямс», 2011. - 1056 с.

7.      Yandex Maps APIs [Электронный ресурс]. - Режим доступа: https://tech.yandex.ru/maps/

.        Bootstrap 3 [Электронный ресурс]. - Режим доступа: http://getbootstrap.com/

.        Руководство по ASP.NET MVC 5 [Электронный ресурс]. - Режим доступа: http://metanit.com/sharp/mvc5/

.        Симан, М. Внедрение зависимостей в .NET. - СпБ. : Питер, 2013. -464 с.

.        Голдштейн, С. Оптимизация приложений на платформе .Net. /Голдштейн С., Зурбалев Д., Флатов И. - Россия : ДМК Пресс, 2014. - 524с.

.        Microsoft developer Network [Электронный ресурс]. - Режим доступа: https://msdn.microsoft.com/ru-ru/.

.        Тамре, Л. Введение в тестирование программного обеспечения / Л. Тамре - М.: Вильямс, 2003 - 368с.

Приложение А

Код программы

using System;

using System.Collections.Generic;

using System.Linq;

using MyPet.Domain.Abstract;

using MyPet.Domain.Entities;

using System.Data.Entity;

namespace MyPet.Domain.Concrete

{

public class AdvRepository : IRepository<Advertizement>

{

private EFDbContext context = new EFDbContext();

public IEnumerable<Advertizement> GetAll()

{

return context.Advertizements.Include("Category").Include("DogBreed").Include("AdvertizementOwner");

}

public Advertizement Get(int id)

{

return context.Advertizements.Include("Category").Include("DogBreed").Include("AdvertizementOwner").FirstOrDefault(x=>x.AdvertizementId==id);

}

public void Create(Advertizement adv)

{.Advertizements.Add(adv);

}

public void Update(Advertizement adv)

{.Entry(adv).State = EntityState.Modified;

}

public IEnumerable<Advertizement> Find(Func<Advertizement, Boolean> predicate)

{

return context.Advertizements.Include("Category").Include("DogBreed").Include("AdvertizementOwner").Where(predicate).ToList();

}

public void Delete(int id)

{

Advertizement adv = context.Advertizements.Find(id);

if (adv != null).Advertizements.Remove(adv);

}

public void Save()

{.SaveChanges();

}

}

}

using MyPet.Domain.Entities;

using System.Data.Entity;

usinSystem.Data.Entity.ModelConfiguration.Conventions;

namespace MyPet.Domain.Concrete

{

public class EFDbContext : DbContext

{

public DbSet<Reward> Rewards { get; set; }

public DbSet<Role> Roles { get; set; }

public DbSet<User> Users { get; set; }

public DbSet<DogBreed> DogBreeds { get; set; }

public DbSet<Profile> Profiles { get; set; }

public DbSet<Pet> Pets { get; set; }

public DbSet<Message> Messages { get; set; }

public DbSet<Friend> Friends { get; set; }

public DbSet<Advertizement> Advertizements { get; set; }

public DbSet<AdvertizementCategory> AdvertizementCategories { get; set; }

public DbSet<Review> Reviews { get; set; }

}

}

using System.Linq;

using System.Collections.Generic;

using System.Web;

using System.Web.Mvc;

using System.Security.Claims;

using System.Data.Entity;

using Microsoft.Owin.Security;

using MyPet.WebUI.Models.ViewModels; // пространство имен LoginViewModel

using MyPet.Domain.Entities; // пространство имен моделей

using MyPet.Domain.Concrete;

using MyPet.Domain.Abstract;

using System.Threading.Tasks;

using MyPet.WebUI.Models;

using System.IO;

using System;

using ImageResizer;

using System.Text.RegularExpressions;

namespace MyPet.WebUI.Controllers

{

public class AccountController : Controller

{

private IMyPetRepository repository;

private IRepository<User> userRepository;

private IRepository<Profile> profRepository;

public AccountController(IRepository<User> userRepo, IMyPetRepository repoAll, IRepository<Profile>profRepo )

{

this.userRepository = userRepo;

this.repository = repoAll;

this.profRepository = profRepo;

}

private IAuthenticationManager AuthenticationManager

{

get

{

return HttpContext.GetOwinContext().Authentication;

}

[HttpPost]

public ActionResult Login(LoginModel model)

{

if (ModelState.IsValid)

{

User user = userRepository.GetAll().FirstOrDefault(u => u.Email == model.Email && u.Password == model.Password);

if (user == null)

{.AddModelError("", "Неверный логин или пароль.");

}

else

{

this.Authorise(user);

return RedirectToAction("Details", new { id=user.UserId});

}

}

return View(model);

}

public ActionResult Logout()

{.SignOut();

return RedirectToAction("List", "Advertizements");

}

[NonAction]

private ActionResult UserProfile(int id=0) // bottlenick!! The aportunity to authorise not through login-password

{

if (!Request.IsAuthenticated)

{

User curUser=userRepository.Get(id);

this.Authorise(curUser);

}= User.Identity.GetUserId<int>();

return RedirectToAction("Details", new { id});

}

public ActionResult List(int id=0)

{

if (id == 0)

return View(userRepository.GetAll().Select(x=>x.Profile));

else

{

var user = userRepository.Find(x => x.UserId == id);

if (user != null)

{

return View(user.Select(x => x.Profile));

}

else

return RedirectToAction("UserProfile", "Account", new { id = User.Identity.GetUserId<int>() });

}

}

[Authorize]

public ActionResult Details(int id)

{

var user = userRepository.Get(id);

this.FillViewBag(id);

string path = Server.MapPath(String.Concat("~/ProfilePhotos/", user.UserId.ToString().Trim(), "/").Trim());

string avatarPath = String.Concat("small", this.GetMinNumberInFileNames(path).ToString()).Trim();["AvatarPath"] = avatarPath;

if (user != null)

return View(user.Profile);

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

[Authorize]

public ActionResult Edit()

{

int id = User.Identity.GetUserId<int>();

var prof = userRepository.Get(id).Profile;

if (prof != null)

{.Cities = new string[] { "Минск" }.Concat(repository.Advertizements.Select(x => x.City).OrderBy(x => x)).Distinct();

return View(prof);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

[HttpPost]

[Authorize]

public ActionResult Edit(Profile prof, HttpPostedFileBase[] uploads)

{

int id = User.Identity.GetUserId<int>();

if (ModelState.IsValid && prof.UserId == id)

{

if (uploads.Where(x => x!=null).FirstOrDefault() != null && prof.HaveImages == false).HaveImages = true;.Update(prof);.Save();= profRepository.Get(prof.UserId);

try

{

if (uploads != null && uploads.Where(x => x!=null).FirstOrDefault() != null)

{

string path = Server.MapPath(String.Concat("~/ProfilePhotos/", prof.UserId.ToString().Trim(), "/").Trim());

int i = this.GetMaxNumberInFileNames(path) + 1;

foreach (var upload in uploads)

{

if (upload != null)

{

if (upload.ContentLength > 0)

{

var versions = new Dictionary<string, string>();

//Define the versions to generate.Add("big", "maxwidth=768&maxheight=1024&format=jpg");.Add("small", "maxwidth=240&maxheight=320&format=jpg");.Add("tiny", "&maxheight=108&format=jpg");//maxwidth=81

//Generate each version

foreach (var suffix in versions.Keys)

{.InputStream.Seek(0, SeekOrigin.Begin);

//Let the image builder add the correct extension based on the output file type

ImageBuilder.Current.Build(

new ImageJob(upload.InputStream,

String.Concat(path, suffix, i.ToString()),

new Instructions(versions[suffix]),

false, true));

}

}++;

}

}

}

}

catch (NullReferenceException) { }

return RedirectToAction("Details", new { id = prof.UserId });

}

else

{.Cities = new string[] { "Минск" }.Concat(repository.Advertizements.Select(x => x.City).OrderBy(x => x)).Distinct();

return View(prof);

}

}

[Authorize]

public ActionResult EditProfileAjax()

{

int id = User.Identity.GetUserId<int>();

var prof = userRepository.Get(id).Profile;.Cities = new string[] { "Минск" }.Concat(repository.Advertizements.Select(x => x.City).OrderBy(x => x)).Distinct();

if (prof != null)

return PartialView(prof);

else return("UserProfile", "Account", new { id });

}

[HttpPost]

[Authorize]

public ActionResult EditProfileAjax(Profile prof)

{

int id=User.Identity.GetUserId<int>();

if (ModelState.IsValid && prof.UserId==id)

{.Get(id).Profile = prof;.Save();

this.FillViewBag(id);

return PartialView("DetailsPartial", userRepository.Get(prof.UserId).Profile);

}.Cities = new string[] { "Минск" }.Concat(repository.Advertizements.Select(x => x.City).OrderBy(x => x)).Distinct();

return PartialView(prof);

}

[ValidateAntiForgeryToken]

private void Authorise(User user)

{

ClaimsIdentity claim = new ClaimsIdentity("ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.UserId.ToString(), ClaimValueTypes.String));.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, user.Email, ClaimValueTypes.String));.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider",

"OWIN Provider", ClaimValueTypes.String));

if (user.Role != null).AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, user.Role.Name, ClaimValueTypes.String));

.SignOut();.SignIn(new AuthenticationProperties{IsPersistent = true}, claim);

}

private void FillViewBag(int id)

{

var pets = repository.Pets.Where(x => x.UserId == id);.Pets = pets;

var advs = repository.Advertizements.Where(x => x.AdvertizementOwnerId == id);.Advs = advs;

}

public PartialViewResult Vidget()

{

int userId;

Profile profile=null;

string name;

if (Request.IsAuthenticated && int.TryParse(User.Identity.GetUserId<int>().ToString(), out userId))

{= userRepository.Get(userId).Profile;

}

if (profile != null)= profile.FirstName + " " + profile.LastName;

else name = null;

return PartialView((object)name);

}

public ActionResult GetImg(string id)

{

FileInfo file=new FileInfo(Server.MapPath("~/Avatars/default.jpg"));

if (id != null)

{

string[] strs = id.Split(new char[] { '-' });

if (strs.Length == 2 && (new FileInfo(Server.MapPath(String.Concat("~/ProfilePhotos/", strs[0].Trim(), "/", strs[1], ".jpg").Trim()))).Exists)

{= new FileInfo(Server.MapPath(String.Concat("~/ProfilePhotos/", strs[0].Trim(), "/", strs[1], ".jpg").Trim()));

}

else

{

Profile prof=profRepository.Find(x=>x.UserId==int.Parse(strs[0])).FirstOrDefault();

if (prof.Sex)= new FileInfo(Server.MapPath("~/Avatars/default.jpg"));

else= new FileInfo(Server.MapPath("~/Avatars/default2.jpg"));

}

}

if (file.Exists)

return File(file.FullName, "text/plain", file.Name);

else return Content("");

}

[Authorize]

[HttpPost]

public ActionResult DeletePhoto(DeletePhotoModel delPhModel)

{

int authUserId = User.Identity.GetUserId<int>();

if (delPhModel.WhoCanDeleteId == authUserId && delPhModel.OwnerId != 0 && delPhModel.PhotoNumber != 0)

{

DirectoryInfo di = new DirectoryInfo(Server.MapPath(String.Concat("~/ProfilePhotos/", delPhModel.OwnerId.ToString().Trim()).Trim()));

if (di.Exists)

{

foreach (var file in di.GetFiles())

{

int fotoNumberLenght = delPhModel.PhotoNumber.ToString().Length;

int fileNameLength = Path.GetFileNameWithoutExtension(file.Name).Length;

if (file.Name.Contains(delPhModel.PhotoNumber.ToString()) &&

(Path.GetFileNameWithoutExtension(file.Name).LastIndexOf(delPhModel.PhotoNumber.ToString()) == fileNameLength - fotoNumberLenght))

{.Delete();

}

}

if (di.GetFiles().Length == 0)

{.Delete();

var prof = profRepository.Find(x => x.UserId == delPhModel.OwnerId).FirstOrDefault();

if (prof != null).HaveImages = false;.Save();

}

}

}

return null;

}

private int GetMaxNumberInFileNames(string path)

{

//var path = Server.MapPath(String.Concat("~/ProfilePhotos/", prof.UserId.ToString().Trim(), "/").Trim());

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

Regex r = new Regex(@"\d+");

string ddd = di.GetFiles().Select(x => x.Name).FirstOrDefault();

Match teg;

int maxNumberInFileNames = 0;

foreach (string fileName in di.GetFiles().Select(x => x.Name))

{= r.Match(fileName);

if (teg.Success && int.Parse(teg.ToString()) > maxNumberInFileNames)= int.Parse(teg.ToString());

}

return maxNumberInFileNames;

}

private int GetMinNumberInFileNames(string path)

{

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

Regex r = new Regex(@"\d+");

string ddd = di.GetFiles().Select(x => x.Name).FirstOrDefault();

Match teg;

int minNumberInFileNames = int.MaxValue;

foreach (string fileName in di.GetFiles().Select(x => x.Name))

{= r.Match(fileName);

if (teg.Success && int.Parse(teg.ToString()) < minNumberInFileNames)= int.Parse(teg.ToString());

}

return minNumberInFileNames==int.MaxValue?0:minNumberInFileNames;

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MyPet.Domain.Abstract;

using MyPet.Domain.Entities;

using MyPet.WebUI.Models;

using MyPet.WebUI.Models.ViewModels;

using System.IO;

using ImageResizer;

namespace MyPet.WebUI.Controllers

{

public class AdvertizementsController : Controller

{

// GET: Advertizements

private IMyPetRepository repository;

private IRepository<Advertizement> advRepository;

public int PageSize = 3;

public AdvertizementsController(IMyPetRepository repo, IRepository<Advertizement> advrepo)

{

this.repository = repo;

this.advRepository = advrepo;

}

public ActionResult MyAdvs(int? id)

{

if (id == null)= User.Identity.GetUserId<int>();

var advs = advRepository.Find(x => x.AdvertizementOwnerId == id);

if (advs != null)

return View(advs);

else

return RedirectToAction("List");

}

public ActionResult Details(int id)

{

var adv = advRepository.Get(id);

List<string[]> advPhotos=null;

if (adv != null)

{

DirectoryInfo dir = new DirectoryInfo(Server.MapPath(String.Concat("~/AdvPhotos/", id).Trim()));

if(dir!=null && dir.Exists)

{= new List<string[]>();

IEnumerable<FileInfo> files = dir.GetFiles();

string[] curFiles;

int filesGroupCount=files.Where(x=>x.Name.Contains("tiny")).Count();

for(int i=1; i<filesGroupCount+1; i++)

{= new string[3];[0] = Path.GetFileNameWithoutExtension(files.FirstOrDefault(x => x.Name.Contains("big") && x.Name.Contains(i.ToString())).Name);[1] = Path.GetFileNameWithoutExtension(files.FirstOrDefault(x => x.Name.Contains("small") && x.Name.Contains(i.ToString())).Name);[2]=Path.GetFileNameWithoutExtension(files.FirstOrDefault(x=>x.Name.Contains("tiny") && x.Name.Contains(i.ToString())).Name);.Add(curFiles);

}

}["AdvPhotos"] = advPhotos;.ReviewsCount = (repository.Reviews.Where(x => x.AdvertizementId == adv.AdvertizementId).Count());.AdvsCount = advRepository.Find(x => (x.AdvertizementOwnerId == adv.AdvertizementOwnerId) && (x.AdvertizementId != id)).Count();

return View(adv);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

public ActionResult Create()

{

Advertizement adv = new Advertizement();.Categories = repository.AdvertizementCategories;.DogBreeds = repository.DogBreeds;

return View(adv);

}

[HttpPost]

public ActionResult Create(Advertizement adv, HttpPostedFileBase[] uploads)

{

if (ModelState.IsValid)

{.DateAndTime = DateTime.Now;.AdvertizementOwnerId = User.Identity.GetUserId<int>();.City = repository.Profiles.FirstOrDefault(x => x.UserId == User.Identity.GetUserId<int>()).City;

if (uploads.Where(x => x.ContentLength > 0).FirstOrDefault() != null).HaveImages = true;.Create(adv);.Save();= advRepository.Get(adv.AdvertizementId);

if (uploads!=null && uploads.Where(x=>x.ContentLength>0).FirstOrDefault()!=null)

{

var path = Server.MapPath(String.Concat("~/AdvPhotos/", adv.AdvertizementId.ToString().Trim(), "/").Trim());

Directory.CreateDirectory(path);

int i=1;

foreach(var upload in uploads)

{

if(upload.ContentLength>0)

{

var versions = new Dictionary<string, string>();

//Define the versions to generate.Add("big", "maxwidth=768&maxheight=1024&format=jpg");.Add("small", "maxwidth=240&maxheight=320&format=jpg");.Add("tiny", "&maxheight=108&format=jpg");//maxwidth=81

//Generate each version

foreach (var suffix in versions.Keys)

{.InputStream.Seek(0, SeekOrigin.Begin);

//Let the image builder add the correct extension based on the output file type

ImageBuilder.Current.Build(

new ImageJob( upload.InputStream,

String.Concat(path, suffix, i.ToString()),

new Instructions(versions[suffix]),

false,true));

}

}++;

}

}.Advs = advRepository.Find(x => x.AdvertizementOwnerId == adv.AdvertizementOwnerId);

return RedirectToAction("Details", new { id=adv.AdvertizementId});

}

else

{.Categories = repository.AdvertizementCategories;.DogBreeds = repository.DogBreeds;

return View(adv);

}

}

public ActionResult Edit(int id)

{

var adv = advRepository.Get(id);

if (adv != null)

{.Categories = repository.AdvertizementCategories;.DogBreeds = repository.DogBreeds;

return View(adv);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

[HttpPost]

public ActionResult Edit(Advertizement adv, HttpPostedFileBase[]uploads)

{

if (ModelState.IsValid)

{.DateAndTime = DateTime.Now;.City = repository.Profiles.FirstOrDefault(x => x.UserId == User.Identity.GetUserId<int>()).City;

if (uploads.Where(x => x != null).FirstOrDefault() != null && adv.HaveImages == false).HaveImages = true;.Update(adv);.Save();= advRepository.Get(adv.AdvertizementId);

try

if (uploads != null && uploads.Where(x=>x.ContentLength>0).FirstOrDefault()!=null)

{

var path = Server.MapPath(String.Concat("~/AdvPhotos/", adv.AdvertizementId.ToString().Trim(), "/").Trim());

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

int existingPhotoCount = di.GetFiles().Length / 3;

// здесь вместо i надо указать номер файла следующий за последним в директории

int i = existingPhotoCount + 1;

foreach (var upload in uploads)

{

if (upload != null)

{

if (upload.ContentLength > 0)

{

var versions = new Dictionary<string, string>();

//Define the versions to generate.Add("big", "maxwidth=768&maxheight=1024&format=jpg");.Add("small", "maxwidth=240&maxheight=320&format=jpg");.Add("tiny", "&maxheight=108&format=jpg");//maxwidth=81

//Generate each version

foreach (var suffix in versions.Keys)

{.InputStream.Seek(0, SeekOrigin.Begin);

//Let the image builder add the correct extension based on the output file type

ImageBuilder.Current.Build(

new ImageJob(upload.InputStream,

String.Concat(path, suffix, i.ToString()),

new Instructions(versions[suffix]),

false, true));

}

}++;

}

}

}

}

catch (NullReferenceException) { }.Advs = advRepository.Find(x => x.AdvertizementOwnerId == adv.AdvertizementOwnerId);

return RedirectToAction("Details", new { id = adv.AdvertizementId });

}

else

{.Categories = repository.AdvertizementCategories;.DogBreeds = repository.DogBreeds;

return View(adv);

}

}

//public ActionResult EditAjax(int id)

//{

// var adv = advRepository.Get(id);

// if (adv != null)

// {

// ViewBag.Categories = repository.AdvertizementCategories;

// ViewBag.DogBreeds = repository.DogBreeds;

// return PartialView(adv);

// }

// else return

// RedirectToAction("Details", "Account", new { id = User.Identity.GetUserId<int>() });

//}

//[HttpPost]

//public ActionResult EditAjax(Advertizement adv)

//{

// int id = User.Identity.GetUserId<int>();

// if (ModelState.IsValid && adv.AdvertizementOwnerId == id)

// {

// advRepository.Update(adv);

// advRepository.Save();

// adv = advRepository.Get(adv.AdvertizementId);

// return PartialView("DetailsPartial", adv);

// }

// return PartialView(adv);

//}

[Authorize]

public ActionResult Delete(int id)

{

var adv=advRepository.Get(id);

int userid = User.Identity.GetUserId<int>();

if (adv != null && adv.AdvertizementOwnerId == userid)

{.Delete(id);.Save();

var path = Server.MapPath(String.Concat("~/AdvPhotos/", id.ToString().Trim(), "/"));

DirectoryInfo di = new DirectoryInfo(path);

if(di!=null && di.Exists)

{

foreach (var file in di.GetFiles())

{.Delete();

}.Delete();

}

return RedirectToAction("MyAdvs");

}

else return RedirectToAction("DetailsPartial", "Account", new { id = userid });

}

[Authorize]

[HttpPost]

public ActionResult DeletePhoto(DeletePhotoModel delPhModel)

{

int authUserId = User.Identity.GetUserId<int>();

if (delPhModel.WhoCanDeleteId == authUserId && delPhModel.OwnerId!=0 && delPhModel.PhotoNumber!=0)

{

DirectoryInfo di = new DirectoryInfo(Server.MapPath(String.Concat("~/AdvPhotos/",delPhModel.OwnerId.ToString().Trim()).Trim()));

if(di.Exists)

{

foreach(var file in di.GetFiles())

{

int fotoNumberLenght=delPhModel.PhotoNumber.ToString().Length;

int fileNameLength=Path.GetFileNameWithoutExtension(file.Name).Length;

if(file.Name.Contains(delPhModel.PhotoNumber.ToString()) &&

(Path.GetFileNameWithoutExtension(file.Name).LastIndexOf(delPhModel.PhotoNumber.ToString()) == fileNameLength-fotoNumberLenght) )

{.Delete();

}

}

if(di.GetFiles().Length==0)

{.Delete();

var adv=advRepository.Find(x => x.AdvertizementId == delPhModel.OwnerId).FirstOrDefault();

if (adv != null).HaveImages = false;

}

}

}

return null;

}

public ViewResult List()

{

return View();

}

public PartialViewResult GetAdvData( int id = 1)

{

PagingInfo pi = new PagingInfo { CurrentPage = id, ItemsPerPage = PageSize, TotalItems = advRepository.GetAll().Count() };

SearchInfo si = new SearchInfo

{= SortWay.MaxDatesFirst,= pi

};

AdvsListViewModel model = new AdvsListViewModel { Advs = si.FilterAdvs(advRepository.GetAll()), PagingInfo = pi };

return PartialView(model);

}

public PartialViewResult Filter()

{

return PartialView(FillSearchInfoByLists(

new SearchInfo {PagingInfo=new PagingInfo

{= 1,= PageSize,= advRepository.GetAll().Count()

}, WayToSort=SortWay.MaxDatesFirst }));

}

[HttpPost]

public PartialViewResult Filter(SearchInfo si)

{

//System.Threading.Thread.Sleep(3000);

IEnumerable<Advertizement> advs =si.FilterAdvs(advRepository.GetAll());

PagingInfo pi = si.PagingInfo;.ItemsPerPage = this.PageSize;

return PartialView("GetAdvData", new AdvsListViewModel { Advs=advs, PagingInfo=pi});

}

public ActionResult GetImg(string id)

{

//string path = (filename == null || filename == "") ? @"D:\ИИТ БГУИР\Курсач\MyRepetitor\MyRepetitor.WebUI\AdvPhotos\73\" + filename + ".jpg" : (@"D:\ИИТ БГУИР\Курсач\MyRepetitor\MyRepetitor.WebUI\AdvPics\default.jpg");

if (id != null)

{

string[] strs = id.Split(new char[] { '-' });

if(strs.Length<2)

return Content("");

FileInfo file;= new FileInfo(Server.MapPath(String.Concat("~/AdvPhotos/",strs[0].Trim(),"/", strs[1], ".jpg").Trim()));

if (file.Exists)

return File(file.FullName, "text/plain", file.Name);

else return Content("");

}

else return Content("");

}

// JsonResults methods for ajax requests

public JsonResult GetAdvsJson(SearchInfo si)

{

var data = si.FilterAdvsWithoutPaging(advRepository.GetAll()).Select(a => new {= a.Topic,= Url.Action("Details", "Advertizements", new { id=a.AdvertizementId}),= String.Concat(a.City??"" , ", " , a.Adress??""),=a.Price,=String.Concat(a.AdvertizementOwner.FirstName, " ", a.AdvertizementOwner.LastName),= Url.Action("Details", "Account", new { id = a.AdvertizementOwnerId })

});

return Json(data, JsonRequestBehavior.AllowGet);

}

private SearchInfo FillSearchInfoByLists(SearchInfo searchInfo)

{.Categories = repository.AdvertizementCategories;.DogBreeds = repository.DogBreeds;.Cities = new string[] { "Минск" }.Concat(repository.Advertizements.Where(x=>x.City!=null).Select(x => x.City).OrderBy(x => x)).Distinct();

return searchInfo;

}

}

}

using MyPet.Domain.Abstract;

using MyPet.Domain.Entities;

using MyPet.WebUI.Models;

using MyPet.WebUI.Models.ViewModels;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

namespace MyPet.WebUI.Controllers

{

[Authorize]

public class MessageController : Controller

{

// GET: Message

private IMyPetRepository repository;

private IRepository<Message> msgRepository;

//private int authorisedUserId = User.Identity.GetUserId<int>();

public MessageController(IMyPetRepository repo, IRepository<Message> mesrepo)

{

this.repository = repo;

this.msgRepository = mesrepo;

}

public ActionResult New(int id)

{

int authorisedUserId=User.Identity.GetUserId<int>();

var msgs=msgRepository.GetAll().Where(x => (x.AuthorId == id && x.ReceiverId == authorisedUserId) || (x.ReceiverId == id && x.AuthorId == authorisedUserId))

.OrderByDescending(x => x.DateAndTime).Take(10).OrderBy(x=>x.DateAndTime);

IEnumerable<Message> willBeViewedMsgs = msgs.Where(x => x.HasBeenViewed == false && User.Identity.GetUserId<int>() == x.ReceiverId);

foreach(var v in willBeViewedMsgs)

{.HasBeenViewed=true;

}.Save();.ReceiverId = id;

return View(msgs);

}

[HttpPost]

public ActionResult New(Message msg)

{

if (msg.Text != null && msg.AuthorId == User.Identity.GetUserId<int>())

{.DateAndTime = DateTime.Now;

Message msgBeforeSavingInDB = msg;.Create(msg);.Save();

}

IEnumerable<Message> msgsToShow = msgRepository.Find(x => (x.AuthorId == msg.ReceiverId && x.ReceiverId == msg.AuthorId && x.HasBeenViewed == false)

|| (x.DateAndTime == msg.DateAndTime && x.AuthorId == msg.AuthorId && x.ReceiverId == msg.ReceiverId && x.Text == msg.Text));

foreach (var v in msgsToShow)

{

if (v.AuthorId != msg.AuthorId).HasBeenViewed = true;

}.Save();

if (msgsToShow != null)

{

return PartialView("GetNextMsgs", msgsToShow);

}

else return null;

}

public ActionResult List()

{

int authorisedUserId = User.Identity.GetUserId<int>();

var receivedMsgsLists = msgRepository.Find(x => x.ReceiverId == authorisedUserId)

.GroupBy(x => x.AuthorId).ToArray();

List<MsgAndUnViewedMsgsCount> lastReceivedMsgsFromDifferentAuthors=new List<MsgAndUnViewedMsgsCount>();

foreach(var msgs in receivedMsgsLists)

{

int count=msgs.Where(x => x.ReceiverId == authorisedUserId && x.HasBeenViewed == false).Count();

Message lastCurMsg=msgs.OrderByDescending(x=>x.DateAndTime).FirstOrDefault();.Add(new MsgAndUnViewedMsgsCount { Message = lastCurMsg, UnviewedMsgsCount = count, ReceiverProfile = repository.Profiles.Where(x => x.UserId == lastCurMsg.ReceiverId).FirstOrDefault()});

}

var sentMsgsLists = msgRepository.Find(x => x.AuthorId == authorisedUserId)

.GroupBy(x => x.ReceiverId).ToArray();

List<MsgAndUnViewedMsgsCount> lastSentMsgsFromDifferentAuthors=new List<MsgAndUnViewedMsgsCount>();

foreach(var msgs in sentMsgsLists)

{

int count = 0;

Message lastCurMsg = msgs.OrderByDescending(x => x.DateAndTime).FirstOrDefault();.Add(new MsgAndUnViewedMsgsCount { Message = lastCurMsg, UnviewedMsgsCount = count, ReceiverProfile=repository.Profiles.Where(x=>x.UserId==lastCurMsg.ReceiverId).FirstOrDefault()});

}

List<MsgAndUnViewedMsgsCount> resultMsgs = new List<MsgAndUnViewedMsgsCount>();

foreach(var msg in lastReceivedMsgsFromDifferentAuthors)

{

MsgAndUnViewedMsgsCount ms = lastSentMsgsFromDifferentAuthors.Where(x =>.Message.AuthorId==msg.Message.ReceiverId

&& x.Message.ReceiverId==msg.Message.AuthorId).FirstOrDefault();

DateTime dt=(ms!=null?ms.Message.DateAndTime:msg.Message.DateAndTime);

if(dt > msg.Message.DateAndTime).Add(ms);

else resultMsgs.Add(msg);

}

return View(resultMsgs.OrderByDescending(x=>x.Message.DateAndTime));

}

public JsonResult GetUnviewedMsgsCountJson()

{

int authorisedUserId=User.Identity.GetUserId<int>();

var data = msgRepository.Find(x => (x.ReceiverId == authorisedUserId) && x.HasBeenViewed == false).Count();

return Json(data, JsonRequestBehavior.AllowGet);

}

public ActionResult GetNextMsgs(PresentedMsgsModelObj presMsgsObj)

{

IEnumerable<Message> newNextMsgs = msgRepository.Find(x => (x.ReceiverId == presMsgsObj.ReceiverId && x.AuthorId == presMsgsObj.AuthorId) || (x.ReceiverId == presMsgsObj.AuthorId && x.AuthorId == presMsgsObj.ReceiverId)).(x => x.DateAndTime).(presMsgsObj.PresentedMsgsCount).(10).OrderBy(x=>x.DateAndTime);

IEnumerable<Message> willBeViewedMsgs = newNextMsgs.Where(x => x.HasBeenViewed == false && User.Identity.GetUserId<int>() == x.ReceiverId);

foreach(var v in willBeViewedMsgs)

{.HasBeenViewed=true;

}.Save();

if (newNextMsgs.Count() != 0)

return PartialView(newNextMsgs);

else return null;

}

// in this method property PresentedMsgsModelObj.PresentedMsgsCount is not nessecary, because the method returns new unViewede msgs

public ActionResult GetNewMsgs(PresentedMsgsModelObj presMsgsObj)

{

IEnumerable<Message> newMsgs = msgRepository.(x => x.ReceiverId == presMsgsObj.AuthorId && x.AuthorId == presMsgsObj.ReceiverId && x.HasBeenViewed==false).(x => x.DateAndTime);

// in this foreach we are mark this msgs as they has been viewed

foreach (var v in newMsgs)

{.HasBeenViewed = true;

}.Save();

if (newMsgs.Count() != 0)

return PartialView("GetNextMsgs",newMsgs);

else return null;

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MyPet.Domain.Entities;

using MyPet.Domain.Abstract;

using MyPet.WebUI.Models;

using MyPet.WebUI.Models.ViewModels;

using ImageResizer;

using System.IO;

using System.Text.RegularExpressions;

namespace MyRepetitor.WebUI.Controllers

{

public class PetsController : Controller

{

private IRepository<Pet> petsRepository;

private IMyPetRepository repository;

public PetsController(IRepository<Pet> petsRepo, IMyPetRepository repo)

{

this.petsRepository = petsRepo;

this.repository = repo;

}

public ActionResult MyPets(int id=0)

{

var pets = petsRepository.Find(x => x.UserId ==id);

if (pets != null)

return View(pets);

else return RedirectToAction("List");

}

public ActionResult List(int id=0)

{

if (id == 0)

return View(petsRepository.GetAll());

else

{

var pet=petsRepository.Find(x=>x.PetId==id);

if (pet != null)

return View(pet);

else

return RedirectToAction("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

}

public ActionResult Details(int id)

{

var pet = petsRepository.Get(id);

List<string[]> petPhotos = null;

string path = Server.MapPath(String.Concat("~/PetPhotos/", id).Trim());

if (pet != null)

{

DirectoryInfo dir = new DirectoryInfo(Server.MapPath(String.Concat("~/PetPhotos/", id).Trim()));

if (dir != null && dir.Exists && dir.GetFiles().Length>0)

{

IEnumerable<int> numbers = this.GetPhotoNumberCollection(path);= new List<string[]>();

IEnumerable<FileInfo> files = dir.GetFiles();

string[] curFiles;

foreach (var v in numbers)

{= new string[3];[0] = Path.GetFileNameWithoutExtension(files.FirstOrDefault(x => x.Name.Contains(String.Concat("big", v.ToString()).Trim())).Name);[1] = Path.GetFileNameWithoutExtension(files.FirstOrDefault(x => x.Name.Contains(String.Concat("small", v.ToString()).Trim())).Name);[2] = Path.GetFileNameWithoutExtension(files.FirstOrDefault(x => x.Name.Contains(String.Concat("tiny", v.ToString()).Trim())).Name);.Add(curFiles);

}

}["PetPhotos"] = petPhotos;

string petAvatarPath = String.Concat("small", this.GetMinNumberInFileNames(path).ToString()).Trim();["PetAvatarPath"] = petAvatarPath;

return View(pet);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

public ActionResult EditPet(int id)

{

var pet = petsRepository.Get(id);

if (pet != null)

return View(pet);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

[Authorize]

[HttpPost]

public ActionResult EditPet(Pet pet, HttpPostedFileBase[] uploads)

{

int id = User.Identity.GetUserId<int>();

if (ModelState.IsValid && pet.UserId == id)

{

foreach (var v in pet.Rewards.Where(x => x.PetOwnerId == 0))

{.PetOwnerId = pet.PetId;

}

if (uploads.Where(x => x != null).FirstOrDefault() != null && pet.HaveImages == false).HaveImages = true;.Update(pet);.Save();= petsRepository.Get(pet.PetId);

try

{

if (uploads != null && uploads.Where(x => x != null).FirstOrDefault() != null)

{

string path = Server.MapPath(String.Concat("~/PetPhotos/", pet.PetId.ToString().Trim(), "/").Trim());

int i = this.GetMaxNumberInFileNames(path) + 1;

foreach (var upload in uploads)

{

if (upload != null)

{

if (upload.ContentLength > 0)

{

var versions = new Dictionary<string, string>();

//Define the versions to generate.Add("big", "maxwidth=768&maxheight=1024&format=jpg");.Add("small", "maxwidth=240&maxheight=320&format=jpg");.Add("tiny", "&maxheight=108&format=jpg");//maxwidth=81

//Generate each version

foreach (var suffix in versions.Keys)

{.InputStream.Seek(0, SeekOrigin.Begin);

//Let the image builder add the correct extension based on the output file type

ImageBuilder.Current.Build(

new ImageJob(upload.InputStream,

String.Concat(path, suffix, i.ToString()),

new Instructions(versions[suffix]),

false, true));

}

}++;

}

}

}

}

catch (NullReferenceException) { }

return RedirectToAction("Details", new { id = pet.PetId });

}

else

{.DogBreeds = repository.DogBreeds;

return View(pet);

}

}

public ActionResult EditPetAjax(int id)

{

var pet = petsRepository.Get(id);

if (pet != null)

{.DogBreeds = repository.DogBreeds;

return PartialView(pet);

}

else return("Details", "Account", new { id = User.Identity.GetUserId<int>() });

}

[HttpPost]

public ActionResult EditPetAjax(Pet pet)

{

int id = User.Identity.GetUserId<int>();

if (ModelState.IsValid && pet.UserId == id)

{.Update(pet);.Save();= petsRepository.Get(pet.PetId);

return PartialView("DetailsPartial", pet);

}

return PartialView(pet);

}

public ActionResult Create()

{.DogBreeds = repository.DogBreeds;

return View(new Pet());

}

[HttpPost]

public ActionResult Create(Pet pet)

{

if (ModelState.IsValid)

{.UserId = User.Identity.GetUserId<int>();.Create(pet);.Save();

return View("List", petsRepository.Find(x=>x.Name==pet.Name));

}

else return View(pet);

}

public ActionResult GetImg(string id)

{

FileInfo file = new FileInfo(Server.MapPath("~/Avatars/default-dog-avatar.jpg"));

if (id != null)

{

string[] strs = id.Split(new char[] { '-' });

if (strs.Length == 2 && (new FileInfo(Server.MapPath(String.Concat("~/PetPhotos/", strs[0].Trim(), "/", strs[1], ".jpg").Trim()))).Exists)

{= new FileInfo(Server.MapPath(String.Concat("~/PetPhotos/", strs[0].Trim(), "/", strs[1], ".jpg").Trim()));

}

else

{= new FileInfo(Server.MapPath("~/Avatars/default-dog-avatar.jpg"));

}

}

if (file.Exists)

return File(file.FullName, "text/plain", file.Name);

else return Content("");

}

[Authorize]

[HttpPost]

public ActionResult DeletePhoto(DeletePhotoModel delPhModel)

{

int authUserId = User.Identity.GetUserId<int>();

if (delPhModel.WhoCanDeleteId == authUserId && delPhModel.OwnerId != 0 && delPhModel.PhotoNumber != 0)

{

DirectoryInfo di = new DirectoryInfo(Server.MapPath(String.Concat("~/PetPhotos/", delPhModel.OwnerId.ToString().Trim()).Trim()));

if (di.Exists)

{

foreach (var file in di.GetFiles())

{

int fotoNumberLenght = delPhModel.PhotoNumber.ToString().Length;

int fileNameLength = Path.GetFileNameWithoutExtension(file.Name).Length;

if (file.Name.Contains(delPhModel.PhotoNumber.ToString()) &&

(Path.GetFileNameWithoutExtension(file.Name).LastIndexOf(delPhModel.PhotoNumber.ToString()) == fileNameLength - fotoNumberLenght))

{.Delete();

}

}

if (di.GetFiles().Length == 0)

{.Delete();

var pet = petsRepository.Find(x => x.PetId == delPhModel.OwnerId).FirstOrDefault();

if (pet != null).HaveImages = false;.Save();

}

}

}

return null;

}

[Authorize]

public ActionResult Delete(int id)

{

var pet = petsRepository.Get(id);

int userid = User.Identity.GetUserId<int>();

if (pet != null && pet.UserId == userid)

{.Delete(id);.Save();

var path = Server.MapPath(String.Concat("~/PetsPhotos/", id.ToString().Trim(), "/"));

DirectoryInfo di = new DirectoryInfo(path);

if (di != null && di.Exists)

{

foreach (var file in di.GetFiles())

{.Delete();

}.Delete();

}

return RedirectToAction("List", "Advertizements");

}

else return RedirectToAction("DetailsPartial", "Account", new { id = userid });

}

private int GetMaxNumberInFileNames(string path)

{

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

Regex r = new Regex(@"\d+");

string ddd = di.GetFiles().Select(x => x.Name).FirstOrDefault();

Match teg;

int maxNumberInFileNames = 0;

foreach (string fileName in di.GetFiles().Select(x => x.Name))

{= r.Match(fileName);

if (teg.Success && int.Parse(teg.ToString()) > maxNumberInFileNames)= int.Parse(teg.ToString());

}

return maxNumberInFileNames;

}

private int GetMinNumberInFileNames(string path)

{

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

Regex r = new Regex(@"\d+");

string ddd = di.GetFiles().Select(x => x.Name).FirstOrDefault();

Match teg;

int minNumberInFileNames = int.MaxValue;

foreach (string fileName in di.GetFiles().Select(x => x.Name))

{= r.Match(fileName);

if (teg.Success && int.Parse(teg.ToString()) < minNumberInFileNames)= int.Parse(teg.ToString());

}

return minNumberInFileNames == int.MaxValue ? 0 : minNumberInFileNames;

}

private IEnumerable<int> GetPhotoNumberCollection(string path)

{

Directory.CreateDirectory(path);

DirectoryInfo di = new DirectoryInfo(path);

if (di.Exists && di.GetFiles().Length > 0)

{

Regex r = new Regex(@"\d+");

Match teg;

List<int> numbers = new List<int>();

foreach (string fileName in di.GetFiles().Select(x => x.Name))

{= r.Match(fileName);

if (teg.Success && !(numbers.Contains(int.Parse(teg.ToString())))).Add(int.Parse(teg.ToString()));

}

return numbers.Count > 0 ? numbers : null;

}

else return null;

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MyPet.WebUI.Models.ViewModels;

using MyPet.Domain.Abstract;

using MyPet.Domain.Concrete;

using MyPet.Domain.Entities;

using System.Security.Claims;

using Microsoft.Owin.Security;

namespace MyPet.WebUI.Controllers

{

public class RegistrationController : Controller

{

private IRepository<User> userRepository;

public RegistrationController(IRepository<User> repo)

{

this.userRepository = repo;

}

// GET: Registration

public ActionResult New()

{

return View(new UserModel());

}

[HttpPost]

public ActionResult New(UserModel usermodel)

{

if (ModelState.IsValid)

{

User user = new User() { RoleId = 1, Email = usermodel.YourEmail, Password = usermodel.YourPassword };

Profile profile = new Profile() { FirstName = usermodel.FirstName, LastName = usermodel.LastName, Sex = usermodel.Sex };.Profile = profile;.Create(user);.Save();

int userId = userRepository.Find(x => x.Email == user.Email).FirstOrDefault().UserId;

User userDB = userRepository.Find(x => x.UserId == userId).FirstOrDefault();

this.Authorise(userDB);

return RedirectToAction("Details", "Account", new { id=userId});

}

return View(usermodel);

}

private IAuthenticationManager AuthenticationManager

{

get

{

return HttpContext.GetOwinContext().Authentication;

}

}

[ValidateAntiForgeryToken]

private void Authorise(User user)

{

ClaimsIdentity claim = new ClaimsIdentity("ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.UserId.ToString(), ClaimValueTypes.String));.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, user.Email, ClaimValueTypes.String));.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider",

"OWIN Provider", ClaimValueTypes.String));

if (user.Role != null).AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, user.Role.Name, ClaimValueTypes.String));.SignOut();.SignIn(new AuthenticationProperties { IsPersistent = true }, claim);

}

// method to check that email does not exist in Database

public JsonResult CheckEmail(string YourEmail)

{

if (userRepository.GetAll().Where(m => m.Email == YourEmail).Count()!=0)

{

return Json("Пользователь с таким email уже зарегистрирован", JsonRequestBehavior.AllowGet);

}

else

{

return Json(true, JsonRequestBehavior.AllowGet);

}

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using MyPet.Domain.Abstract;

using MyPet.Domain.Entities;

using MyPet.WebUI.Models;

namespace MyRepetitor.WebUI.Controllers

{

public class ReviewController : Controller

{

// GET: Review

private IMyPetRepository repository;

private IRepository<Review> revRepository;

public ReviewController(IMyPetRepository repo, IRepository<Review> revrepo)

{

this.repository = repo;

this.revRepository = revrepo;

}

public ActionResult GetReviews(int id)

{["AdvertizementId"]=id;

return PartialView(revRepository.Find(x => x.AdvertizementId == id).OrderByDescending(x => x.DateAndTime));

}

[HttpPost]

[Authorize]

public PartialViewResult AddComment(Review review)

{

if (review.Text != null && review.AuthorId == User.Identity.GetUserId<int>())

{.DateAndTime = DateTime.Now;.Create(review);.Save();

var reviews = revRepository.Find(x => x.AdvertizementId == review.AdvertizementId).OrderBy(x => x.DateAndTime);

return PartialView("Comments", reviews);

}

return null;

}

}

}

using MyPet.Domain.Entities;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using MyPet.Domain.Abstract;

using System.ComponentModel.DataAnnotations;

using System.Web.Mvc;

using MyPet.WebUI.Models;

namespace MyPet.WebUI.Models

{

public enum SortWay

{,,,,

};

public class SearchInfo

{

//[HiddenInput(DisplayValue = false)]

public PagingInfo PagingInfo { get; set; }

public SearchInfo()

{

this.Categories = new List<AdvertizementCategory>();

this.DogBreeds = new List<DogBreed>();

this.Cities = new List<string>();

}

[Display(Name = "Спрос / предложение")]

public bool? IsDemand { get; set; }

[Display(Name = "Пол")]

public bool? Sex { get; set; }

[HiddenInput(DisplayValue = false)]

public decimal? PriceMin { get; set; }

[HiddenInput(DisplayValue = false)]

public decimal? PriceMax { get; set; }

[Display(Name = "С выездом на дом")]

public bool? IsWithDeparture { get; set; }

[Display(Name = "Период")]

public string Period { get; set; }

public DateTime? FromDate

{

get

{

if (this.Period == "за сегодня")

return DateTime.Now.AddDays(-1);

else if (this.Period == "за неделю")

return DateTime.Now.AddDays(-7);

else if (this.Period == "за месяц")

return DateTime.Now.AddMonths(-1);

else return null;

}

}

[Display(Name = "Категория объявления")]

public int? CategoryId { get; set; }

public int? DogBreedId { get; set; }

[Display(Name = "Город")]

public string City { get; set; }

[HiddenInput(DisplayValue = false)]

public SortWay WayToSort { get; set; }

public IEnumerable<AdvertizementCategory> Categories { get; set; }

public IEnumerable<DogBreed> DogBreeds { get; set; }

public IEnumerable<string> Cities { get; set; }

public IEnumerable<Advertizement> FilterAdvsWithoutPaging(IEnumerable<Advertizement> parentAdvs)

{

IEnumerable<Advertizement> advs = parentAdvs.Where((x) =>

{

if (this.CategoryId == null || this.CategoryId == 0)

return true;

else return x.CategoryId == this.CategoryId;

}).Where((x) =>

{

if (this.PriceMin == null || this.PriceMax == null)

return true;

else return (x.Price >= this.PriceMin) && (x.Price <= PriceMax);

}).Where((x) =>

{

if (this.DogBreedId == null)

return true;

else return x.DogBreedId == this.DogBreedId;

}).Where((x) =>

{

if (this.City == null)

return true;

else return x.City == this.City;

}).Where((x) =>

{

if (this.FromDate == null)

return true;

else return x.DateAndTime >= this.FromDate;

}).Where((x) =>

{

if (this.IsDemand == null)

return true;

else return x.IsDemand == this.IsDemand;

}).Where((x) =>

{

if (this.Sex == null)

return true;

else return x.Sex == this.Sex;

}).Where((x) =>

{

if (this.IsWithDeparture == null || this.IsWithDeparture == false)

return true;

else return x.IsWithDeparture == this.IsWithDeparture;

});

return advs;

}

public IEnumerable<Advertizement> FilterAdvs(IEnumerable<Advertizement> parentAdvs)

{

IEnumerable<Advertizement> advs = this.FilterAdvsWithoutPaging(parentAdvs);

this.PagingInfo.TotalItems = advs.Count();

if (this.WayToSort == SortWay.MaxDatesFirst)

return advs.OrderByDescending(x => x.DateAndTime).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

if (this.WayToSort == SortWay.MinDatesFirst)

return advs.OrderBy(x => x.DateAndTime).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

else if (this.WayToSort == SortWay.MinPricesFirst)

return advs.OrderBy(x => x.Price).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

else if (this.WayToSort == SortWay.MaxPricesFirst)

return advs.OrderByDescending(x => x.Price).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

else if (this.WayToSort == SortWay.SortByRating)

return advs.OrderByDescending(x => x.DateAndTime).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

else return advs.OrderByDescending(x => x.DateAndTime).Skip((this.PagingInfo.CurrentPage - 1) * this.PagingInfo.ItemsPerPage).Take(this.PagingInfo.ItemsPerPage);

}

}

}

using System;

using System.Globalization;

using System.Security.Claims;

using System.Security.Principal;

namespace MyPet.WebUI.Models

{

public static class IdentityExtensions

{

public static T GetUserId<T>(this IIdentity identity) where T : IConvertible

{

if (identity == null)

{

throw new ArgumentNullException("identity");

}

var ci = identity as ClaimsIdentity;

if (ci != null)

{

var id = ci.FindFirst(ClaimTypes.NameIdentifier);

if (id != null)

{

return (T)Convert.ChangeType(id.Value, typeof(T), CultureInfo.InvariantCulture);

}

}

return default(T);

}

public static string GetUserRole(this IIdentity identity)

{

if (identity == null)

{

throw new ArgumentNullException("identity");

}

var ci = identity as ClaimsIdentity;

string role = "";

if (ci != null)

{

var id = ci.FindFirst(ClaimsIdentity.DefaultRoleClaimType);

if (id != null)= id.Value;

}

return role;

}

}

}

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.ComponentModel.DataAnnotations.Schema;

using System.ComponentModel.DataAnnotations;

namespace MyPet.WebUI.Models.ViewModels

{

public class UserModel

{

[Required(ErrorMessage="Поле 'e-mail' является обязательным для заполнения")]

[RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage = "Некорректный адрес")]

[System.Web.Mvc.Remote("CheckEmail", "Registration")]

[Display(Name = "Email")]

public string YourEmail { get; set; }

[Required(ErrorMessage = "Поле 'пароль' является обязательным для заполнения")]

//[DataType(DataType.Password)]

[StringLength(25, MinimumLength = 6, ErrorMessage="Пароль должен быть не менее 6 символов")]

[Display(Name = "Пароль")]

[UIHint("Password")]

public string YourPassword { get; set; }

[Compare("YourPassword", ErrorMessage = "Пароли не совпадают")]

//[DataType(DataType.Password)]

[Display(Name = "Подтвердите пароль")]

[UIHint("Password")]

public string YourPasswordConfirm { get; set; }

[Display(Name="Имя")]

[Required(ErrorMessage = "Поле 'Имя' является обязательным для заполнения")]

[StringLength(25, MinimumLength = 2, ErrorMessage = "Поле 'Имя' слишком короткое")]

public string FirstName { get; set; }

[StringLength(25, MinimumLength = 2, ErrorMessage = "Поле 'Фамилия' слишком короткое")]

[Display(Name = "Фамилия")]

[Required(ErrorMessage = "Поле 'Фамилия' является обязательным для заполнения")]

public string LastName { get; set; }

[Display(Name = "Пол")]

public bool Sex { get; set; }

[Range(typeof(bool), "true", "true", ErrorMessage="Ознакомьтесь и согласитесь с условиями")]

public bool Accept { get; set; }

}

}

Приложение Б

Трассировочная таблица

Таблица Б - Трассировочная таблица

Пользовательское требование

Функция системы

Вариант использования

1

Регистрация

1.1 1.2 1.3 1.4

Ввод личных данных Ввод e-mail Ввод пароля Подтверждение пароля

Ввод личных данных Ввод e-mail Ввод пароля Подтверждение пароля

2

Авторизация

2.1 2.2

Ввод электронного адреса Ввод пароля

Ввод электронного адреса Ввод пароля

3

Работа с персональными данными

3.1 3.2

Просмотр личных данных Редактирование и сохранение данных

Просмотр личных данных Редактирование и сохранение данных

4

Работа с питомцами

4.1  4.2   4.34.4

Просмотр данных о питомцах Редактирование и сохранение данных о питомцах Добавление питомца Удаление питомца

Просмотр данных о питомцах Редактирование и сохранение данных о питомцах Добавление питомца Удаление питомца

5

Работа с личными объявлениями

5.1  5.2   5.3 5.4 5.5

Просмотр данных объявлений Редактирование и сохранение данных объявлений Добавление объявления Удаление объявления Просмотр отзывов

Просмотр данных объявлений Редактирование и сохранение данных объявлений Добавление объявления Удаление объявления Просмотр отзывов

6

Работа с сообщениями

6.1 6.2 6.3

Просмотр списка диалогов Отправка сообщения Получение сообщения

Просмотр списка диалогов Отправка сообщения Получение сообщения

8

Просмотр результатов поиска

8.1  8.2  8.3  8.4

Просмотр карты с метками объявлений Просмотр информации об объявлении Оставление отзыва и оценки объявлению Отправка сообщения автору объявления

Просмотр карты с метками объявлений Просмотр информации об объявлении Оставление отзыва и оценки объявлению Отправка сообщения автору объявления


Похожие работы на - Программное средство по обмену услугами для владельцев собак

 

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