Интернет-магазин цифровых ключей компьютерных игр

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

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 14.12.2019
Размер файла 1,7 M

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

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

import org.springframework.stereotype.Component;

import ru.discoverivan.gameshop.domain.CartService;

import javax.servlet.http.Cookie;

import javax.servlet.jsp.JspException;

import javax.servlet.jsp.tagext.SimpleTagSupport;

import java.io.IOException;

import java.util.Set;

public class GetCartNumTag extends SimpleTagSupport {

private String cartCookie;

private CartService cartService;

public void setCartCookie(String cartCookie) {

this.cartCookie = cartCookie;

}

@Override

public void doTag() throws JspException, IOException {

cartService = new CartService();

Set<Integer> cart = cartService.getCartFromCookie(cartCookie);

getJspContext().getOut().write(Integer.toString(cart.size()));

}

}

Файл: gameshop\src\main\java\ru\discoverivan\gameshop\validation\RegisterForm.java

package ru.discoverivan.gameshop.validation;

public class RegisterForm {

private String name;

private String email;

private String username;

private String password;

private String passwordConfirm;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getEmail() {

return email;

}

public void setEmail(String email) {

this.email = email;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

public String getPassword() {

return password;

}

public void setPassword(String password) {

this.password = password;

}

public String getPasswordConfirm() {

return passwordConfirm;

}

public void setPasswordConfirm(String passwordConfirm) {

this.passwordConfirm = passwordConfirm;

}

}

Файл: gameshop\src\main\java\ru\discoverivan\gameshop\validation\RegisterFormValidator.java

package ru.discoverivan.gameshop.validation;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Service;

import ru.discoverivan.gameshop.db.dao.CustomerDAO;

import ru.discoverivan.gameshop.db.dao.UserDAO;

import ru.discoverivan.gameshop.db.entity.Customer;

import ru.discoverivan.gameshop.validation.RegisterForm;

import ru.discoverivan.gameshop.validation.ValidationResult;

import java.util.HashMap;

import java.util.Map;

import java.util.regex.Pattern;

@Component

public class RegisterFormValidator {

private UserDAO userDAO;

private CustomerDAO customerDAO;

private Pattern passwordPattern = Pattern.compile("^[_a-zA-Z0-9]{3,30}$");

private Pattern usernamePattern = Pattern.compile("^[a-zA-Z0-9]{2,30}$");

public ValidationResult validate(RegisterForm form){

ValidationResult validationResult = new ValidationResult();

Map<String, String> errors = new HashMap<>();

validationResult.setSuccess(true);

if (!usernamePattern.matcher(form.getUsername()).matches()){

validationResult.setSuccess(false);

errors.put("username", "Имя пользователя должно быть из 2-30 символов и состоять из латинских букв и цифр.");

}

if (userDAO.findByUsername(form.getUsername()) != null){

validationResult.setSuccess(false);

errors.put("username", "Имя пользователя уже используется.");

}

if (!passwordPattern.matcher(form.getPassword()).matches()){

validationResult.setSuccess(false);

errors.put("password", "Пароль должен быть из 3-30 символов и состоять из латинских букв и цифр, а также знака подчеркивания.");

}

if (!form.getPassword().equals(form.getPasswordConfirm())){

validationResult.setSuccess(false);

errors.put("passwordConfirm", "Пароли должны совпадать.");

}

if (customerDAO.findByEmail(form.getEmail()) != null){

validationResult.setSuccess(false);

errors.put("email", "Адрес электронной почты уже используется.");

}

validationResult.setFieldErrors(errors);

return validationResult;

}

@Autowired

public void setUserDAO(UserDAO userDAO) {

this.userDAO = userDAO;

}

@Autowired

public void setCustomerDAO(CustomerDAO customerDAO) {

this.customerDAO = customerDAO;

}

}

Файл: gameshop\src\main\java\ru\discoverivan\gameshop\validation\ValidationResult.java

package ru.discoverivan.gameshop.validation;

import java.io.Serializable;

import java.util.Map;

public class ValidationResult implements Serializable {

private Boolean success;

private Map<String, String> fieldErrors;

public Boolean getSuccess() {

return success;

}

public void setSuccess(Boolean success) {

this.success = success;

}

public Map<String, String> getFieldErrors() {

return fieldErrors;

}

public void setFieldErrors(Map<String, String> fieldErrors) {

this.fieldErrors = fieldErrors;

}

}

Файл: gameshop\src\main\java\ru\discoverivan\gameshop\AppLoader.java

package ru.discoverivan.gameshop;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.stereotype.Service;

import ru.discoverivan.gameshop.db.HibernateUtil;

import ru.discoverivan.gameshop.db.dao.*;

import ru.discoverivan.gameshop.db.entity.Game;

import ru.discoverivan.gameshop.db.entity.Genre;

import ru.discoverivan.gameshop.db.entity.Language;

import ru.discoverivan.gameshop.db.entity.Platform;

import ru.discoverivan.gameshop.domain.AdminService;

import javax.servlet.ServletContextListener;

import java.text.ParseException;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashSet;

import java.util.Set;

public class AppLoader implements ServletContextListener {

private LanguageDAO languageDAO;

private PlatformDAO platformDAO;

private GenreDAO genreDAO;

private GameDAO gameDAO;

private OrderDAO orderDAO;

private AdminService adminService;

@Autowired

public void setOrderDAO(OrderDAO orderDAO) {

this.orderDAO = orderDAO;

}

@Autowired

public void setLanguageDAO(LanguageDAO languageDAO) {

this.languageDAO = languageDAO;

}

@Autowired

public void setPlatformDAO(PlatformDAO platformDAO) {

this.platformDAO = platformDAO;

}

@Autowired

public void setGenreDAO(GenreDAO genreDAO) {

this.genreDAO = genreDAO;

}

@Autowired

public void setGameDAO(GameDAO gameDAO) {

this.gameDAO = gameDAO;

}

@Autowired

public void setAdminService(AdminService adminService) {

this.adminService = adminService;

}

public void loadTest(int count){

orderDAO.clear();

gameDAO.clear();

genreDAO.clear();

platformDAO.clear();

languageDAO.clear();

Genre genre = new Genre();

genre.setName("Action");

adminService.addGenre(genre);

Language language = new Language();

language.setName("Русский");

adminService.addLanguage(language);

Platform platform = new Platform();

platform.setName("PC");

adminService.addPlatform(platform);

Game game = new Game();

for(int i=0;i<count;i++){

game.setTitle("Game "+i);

game.setDescription("Description");

game.setPlatforms(new HashSet<>(platformDAO.getAll()));

game.setLanguages(new HashSet<>(languageDAO.getAll()));

game.setGenres(new HashSet<>(genreDAO.getAll()));

game.setDeveloper("Developer");

game.setReleaseDate(new Date());

game.setPosterImageUrl("https://via.placeholder.com/400x400");

Set<String> screens = new HashSet<>();

screens.add("https://via.placeholder.com/400x400");

game.setScreenshotsUrls(screens);

game.setPrice(i);

adminService.addGame(game);

}

}

public void initBase() {

orderDAO.clear();

gameDAO.clear();

genreDAO.clear();

platformDAO.clear();

languageDAO.clear();

Genre genre = new Genre();

genre.setName("Action");

adminService.addGenre(genre);

Language language = new Language();

language.setName("Русский");

adminService.addLanguage(language);

Platform platform = new Platform();

platform.setName("PC");

adminService.addPlatform(platform);

Game game = new Game();

game.setTitle("Far Cry 5");

game.setDescription("В этот раз действие знаменитой серии Far Cry происходит в Америке.\n" +

"Добро пожаловать в Монтану - округ Хоуп - земли свободных и смелых, захваченные фанатиками Врат Эдема. Дайте отпор Иосифу Сиду и его сторонникам. Разожгите огонь сопротивления.\n" +

"Отправляйтесь в США, сокрушите сектантов в одиночку или с другом, но бойтесь гнева Иосифа Сида и его последователей. Создайте уникального персонажа! Используйте в борьбе с сектантами разнообразную технику.");

game.setPlatforms(new HashSet<>(platformDAO.getAll()));

game.setLanguages(new HashSet<>(languageDAO.getAll()));

game.setGenres(new HashSet<>(genreDAO.getAll()));

game.setDeveloper("Ubisoft");

try {

game.setReleaseDate(new SimpleDateFormat("yyyy-MM-dd").parse("2018-03-27"));

} catch (ParseException e) {

game.setReleaseDate(new Date());

}

game.setPosterImageUrl("https://steamcdn-a.akamaihd.net/steam/apps/552520/header.jpg?t=1527102722");

Set<String> screens = new HashSet<>();

screens.add("https://steamcdn-a.akamaihd.net/steam/apps/552520/ss_54e115519104798a3a2dc55e6de3d4974e144b77.600x338.jpg?t=1527102722");

screens.add("https://steamcdn-a.akamaihd.net/steam/apps/552520/ss_c6f08b3d2e156f705205f882504d3cd96f78cca1.600x338.jpg?t=1527102722");

game.setScreenshotsUrls(screens);

game.setPrice(1999);

adminService.addGame(game);

game = new Game();

game.setTitle("Rise of the Tomb Raider");

game.setDescription("Издание Rise of the Tomb Raider: 20 Year Celebration включает в себя базовую версию игры и сезонный пропуск со всеми доступными дополнениями. Исследуйте поместье Крофт в новом дополнении Blood Ties и защищайте его от зомби в режиме Lara's Nightmare. Боритесь за выживание вместе с друзьями в новом кооперативном онлайн-режиме Endurance и проверьте себя на прочность с новой сложностью «Экстремальное выживание». В пакет дополнительного контента входят костюм и оружие для Лары по мотивам Tomb Raider 3, а также 5 других классических костюмов. Два дополнения доступны для скачивания уже сейчас: в Baba Yaga: The Temple of the Witch вам предстоит исследовать новую загадочную гробницу, полную древних ужасов, а в Cold Darkness Awakened -- отбиваться от полчищ зараженных монстров.");

game.setPlatforms(new HashSet<>(platformDAO.getAll()));

game.setLanguages(new HashSet<>(languageDAO.getAll()));

game.setGenres(new HashSet<>(genreDAO.getAll()));

game.setDeveloper("Square Enix");

try {

game.setReleaseDate(new SimpleDateFormat("yyyy-MM-dd").parse("2016-02-09"));

} catch (ParseException e) {

game.setReleaseDate(new Date());

}

game.setPosterImageUrl("https://steamcdn-a.akamaihd.net/steam/apps/391220/header.jpg?t=1532513501");

screens = new HashSet<>();

screens.add("https://steamcdn-a.akamaihd.net/steam/apps/391220/ss_4ef0868ecfc6b19bc1af18b88cabe33fe8147cf7.600x338.jpg?t=1532513501");

screens.add("https://steamcdn-a.akamaihd.net/steam/apps/391220/ss_3b46aa127290e6ad2f62c125096bf5e901458ad6.600x338.jpg?t=1532513501");

screens.add("https://steamcdn-a.akamaihd.net/steam/apps/391220/ss_2b612bfa62d920b061e900e1f7a975a2de6729ec.600x338.jpg?t=1532513501");

game.setScreenshotsUrls(screens);

game.setPrice(1299);

adminService.addGame(game);

}

public void close(){

HibernateUtil.close();

}

}

Файл: gameshop\src\main\resources\hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory>

<property name="connection.url">jdbc:mysql://localhost:3306/host_gameshop</property>

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="connection.username">host_gameshop</property>

<property name="connection.password">*******</property>

<property name="hibernate.connection.CharSet">utf8</property>

<property name="hibernate.connection.characterEncoding">utf8</property>

<property name="hibernate.connection.useUnicode">true</property>

<property name="hbm2ddl.auto">validate</property>

<property name="show_sql">true</property>

<property name="connection.pool_size">25</property>

<mapping class="ru.discoverivan.gameshop.db.entity.Game" />

<mapping class="ru.discoverivan.gameshop.db.entity.Order" />

<mapping class="ru.discoverivan.gameshop.db.entity.Customer" />

<mapping class="ru.discoverivan.gameshop.db.entity.Admin" />

<mapping class="ru.discoverivan.gameshop.db.entity.Genre" />

<mapping class="ru.discoverivan.gameshop.db.entity.Language" />

<mapping class="ru.discoverivan.gameshop.db.entity.Platform" />

<mapping class="ru.discoverivan.gameshop.db.entity.Product" />

</session-factory>

</hibernate-configuration>

Исходный код клиентской части проекта

Файл: gameshop\src\main\webapp\css\style.scss

@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700&subset=cyrillic,cyrillic-ext');

//COLORS

$main:#f47318;

$main-hover: #ff9604;

$main-bg:#1a1b21;

$main-disabled: #757575;

a{

text-decoration: none !important;

color: #fff;

transition: 0.3s;

}

a:hover{

color: $main;

}

canvas {

width: 100%;

}

.main-button{

display: inline-block;

padding: 5px 10px;

background-color: $main;

text-decoration: none !important;

text-transform: uppercase;

font-weight: bold;

font-size: 20px;

color: #fff !important;

border: 0;

-webkit-appearance: none;

cursor: pointer;

transition: 0.3s;

}

.main-button:hover{

background-color: $main-hover;

}

.main-button-block{

display: block;

text-align: center;

}

.main-button:disabled{

background-color: $main-disabled;

}

#index {

font-family: 'Open Sans', sans-serif;

background-color: $main-bg;

header {

background-color: rgba(0, 0, 0, 0.5);

color: #ffffff;

.bar {

padding-top: 10px;

padding-bottom: 10px;

.title {

float: left;

font-size: 32px;

font-weight: bold;

margin-right: 20px;

color: #fff;

text-decoration: none;

}

.links {

float: left;

margin-top: 14px;

text-transform: uppercase;

a {

text-decoration: none;

display: inline-block;

margin-left: 5px;

margin-right: 5px;

}

}

.right {

float: right;

.admin {

display: inline-block;

margin-left: 5px;

margin-right: 5px;

margin-top: 14px;

}

}

}

}

.banners {

.banner {

display: block;

position: relative;

height: 50vh;

background-position: center;

background-size: cover;

.label-wrap {

position: absolute;

text-transform: uppercase;

color: #fff;

bottom: 15%;

left: 10%;

.label {

padding-left: 5px;

padding-right: 5px;

}

.primary {

font-size: 36px;

font-weight: bold;

background-color: $main;

}

.secondary {

font-size: 22px;

background-color: #000;

}

}

}

}

.games-list {

margin-top: 20px;

.category-title {

display: block;

font-size: 36px;

font-weight: bold;

text-transform: uppercase;

margin-bottom: 10px;

}

.game-card {

display: block;

position: relative;

height: 300px;

overflow: hidden;

background-size: cover !important;

background: no-repeat center;

color: #fff;

margin-bottom: 30px;

.title {

position: absolute;

left: 0;

right: 0;

top: 10px;

display: block;

font-weight: bold;

text-align: center;

text-transform: uppercase;

font-size: 20px;

z-index: 1;

}

.bottom {

position: absolute;

bottom: 10px;

left: 0;

right: 0;

text-align: center;

}

}

.game-card:before {

content: "";

position: absolute;

width: 100%;

height: 100%;

background-color: rgba(0, 0, 0, 0.6);

}

}

}

#game-full{

background-color: $main-bg;

margin-top: 20px;

color: #fff;

.poster{

width: 100%;

img{

width: 100%;

height: auto;

}

}

.price{

margin-top: 10px;

text-align: center;

font-size: 46px;

font-weight: bold;

}

.buy-button{

width: 100%;

button{

width: 100%;

}

}

.buy{

padding-top: 15px;

padding-bottom: 15px;

margin-bottom: 20px;

}

.game-info{

h2{

color: $main;

text-transform: uppercase;

font-size: 18px;

font-weight: bold;

margin-bottom: 2px;

}

.game-description{

text-align: justify;

}

.screenshots{

padding-top: 10px;

img{

width: 100%;

margin-bottom: 30px;

}

}

.game-title{

text-transform: uppercase;

font-weight: bold;

font-size: 36px;

}

.tech-info{

color: #fff;

font-size: 15px;

margin-bottom: 30px;

td{

padding-top: 2px;

padding-bottom: 2px;

vertical-align: middle;

}

.name{

font-weight: bold;

padding-right: 30px;

}

}

}

}

#order{

margin-top: 20px;

color: #fff;

h1, h2{

font-weight: bold;

}

table{

margin-top: 20px;

width: 100%;

color: #fff;

td{

padding-bottom: 20px;

}

.image{

width: 1%;

white-space:nowrap;

img{

max-width: 250px;

max-height: 250px;

}

}

.title{

padding-left: 20px;

font-weight: bold;

font-size: 24px;

}

.price{

font-size: 30px;

}

.delete{

text-align: right;

button{

margin-top: 14px;

}

}

}

.order-footer{

margin-top: 40px;

.back{

margin-top: 20px;

text-align: left;

text-transform: uppercase;

font-size: 20px;

}

.total{

text-align: right;

.label{

font-size: 24px;

text-transform: uppercase;

}

.price{

margin-left: 10px;

font-size: 46px;

font-weight: bold;

text-transform: uppercase;

line-height: 40px;

}

}

}

.input-block{

margin-top: 40px;

text-align: right;

button{

margin: auto;

}

}

.buy-something{

text-align: center;

}

.success{

margin-top: 20px;

}

}

#account-index{

color: #fff;

margin-top: 20px;

h1{

font-weight: bold;

}

h3{

margin-top: 15px;

margin-bottom: 10px;

}

table{

vertical-align: middle;

td, tr{

vertical-align: middle;

}

.buttons{

text-align: right;

}

}

.order-details{

margin-bottom: 20px;

table{

width: 100%;

img{

max-height: 150px;

max-width: 350px;

}

color: #fff;

}

}

}

#register{

@extend #login;

.tooltip{

.tooltip-inner{

max-width: 400px;

text-align: left !important;

}

}

.is-invalid{

border: #dc3545 solid 3px !important;

}

}

#login{

color: #fff;

display: -ms-flexbox;

display: -webkit-box;

display: flex;

-ms-flex-align: center;

-ms-flex-pack: center;

-webkit-box-align: center;

align-items: center;

-webkit-box-pack: center;

justify-content: center;

padding-top: 40px;

padding-bottom: 40px;

background-color: $main-bg;

h1{

font-size: 28px;

font-weight: bold;

text-transform: uppercase;

padding-bottom: 6px;

}

.form-signin {

width: 100%;

max-width: 330px;

padding: 15px;

margin: 0 auto;

text-align: center;

button{

display: block;

width: 100%;

}

}

.form-signin .checkbox {

font-weight: 400;

}

.form-signin .form-control {

position: relative;

box-sizing: border-box;

height: auto;

padding: 10px;

font-size: 16px;

}

.form-signin .form-control:focus {

z-index: 2;

}

.form-signin input[type="text"] {

margin-bottom: 10px;

}

.form-signin input[type="password"] {

margin-bottom: 10px;

}

.form-signin input[type="email"] {

margin-bottom: 10px;

}

.alert{

margin-top: 10px;

}

.back{

display: block;

padding-top: 10px;

text-transform: uppercase;

}

}

#admin{

header {

margin-bottom: 60px;

}

#admin-index{

padding-top: 20px;

.button-block{

background-color: #eaeaea;

border-top: 6px $main solid;

display: block;

width: 100%;

padding: 25px;

cursor: pointer;

color: #000 !important;

margin-bottom: 20px;

img{

width: 100%;

padding-left: 20%;

padding-right: 20%;

padding-bottom: 10%;

max-height: 400px;

}

p{

text-align: center;

font-size: 24px;

font-weight: bold;

margin: 0;

}

}

}

.edit-list {

margin-top:20px;

.buttons{

text-align: right;

}

.remove-form{

display: inline-block;

}

}

.edit-add{

margin-top:20px;

}

.edit-init{

margin-top:20px;

margin-bottom: 20px;

}

#game{

.title{

padding-top: 10px;

.add-btn{

margin-top:5px;

text-align: right;

}

}

.pages{

text-align: center;

.pager{

display: inline-block;

margin: auto;

}

}

.screenshots{

input{

margin-bottom: 10px;

}

}

}

#admin-stats{

.load{

img{

margin:auto;

}

text-align: center;

}

.stats-block{

background-color: #eaeaea;

border-top: 6px $main solid;

display: block;

padding: 25px;

width: 100%;

margin-bottom: 30px;

text-align: center;

.number{

font-size: 72px;

font-weight: bold;

}

.label{

font-size: 24px;

text-transform: uppercase;

}

}

}

}

#error{

.wrapper{

display: flex;

justify-content: center;

align-items: center;

height: 100vh;

width: 100%;

text-align: center;

.error-block{

img{

height: 150px;

width: auto;

}

.code{

font-size: 100px;

line-height: 100px;

color: #fff;

font-weight: bold;

}

.description{

font-size: 26px;

color: #fff;

padding-bottom: 20px;

}

}

}

}

Файл: gameshop\src\main\webapp\js\admin.js

initialize();

function initialize() {

if ($("#admin-settings").length) {

var options = {

beforeSubmit: addNewAdminBefore,

success: addNewAdminSuccess,

data_type: 'json'

};

$('#admin-settings .add-admin').ajaxForm(options);

options = {

beforeSubmit: deleteAdminBefore,

success: deleteAdminSuccess,

data_type: 'json'

};

$('#admin-settings .remove-admin').ajaxForm(options);

}

if ($("#game").length) {

checkScreenFieldButtons();

}

if ($("#admin-product-import").length) {

var options = {

beforeSubmit: productImportBefore,

success: productImportSuccess,

error: productImportError,

data_type: 'json'

};

$('#admin-product-import .external-form').ajaxForm(options);

}

if ($("#admin-product-list").length) {

var options = {

beforeSubmit: productListBefore,

success: productListSuccess,

error: productListError,

data_type: 'json'

};

$('#admin-product-list .external-form').ajaxForm(options);

}

if ($("#admin-stats").length) {

loadStats();

}

}

function addNewAdminBefore(formData, jqForm, options) {

$("#admin-settings .alert-danger").slideUp("fast");

$("#admin-settings .alert-success").slideUp("fast");

$("#admin-settings .add-admin button").attr("disabled", "disabled");

}

function addNewAdminSuccess(responseText, statusText, xhr, $form) {

$("#admin-settings .add-admin button").removeAttr("disabled");

if (responseText === "0"){

$("#admin-settings .alert-danger").slideDown("fast");

}

if (responseText === "1"){

$("#admin-settings .alert-success").slideDown("fast");

location.reload();

}

}

function deleteAdminBefore() {

$("#admin-settings .admin-list .alert").slideUp("fast");

}

function deleteAdminSuccess(responseText, statusText, xhr, $form) {

if (responseText === "1"){

$form.parent().parent().slideUp("fast");

} else {

$("#admin-settings .admin-list .alert").slideDown("fast");

}

}

function checkScreenFieldButtons() {

$(".screenshots button[name='addScreen']").attr("disabled", false);

$(".screenshots button[name='removeScreen']").attr("disabled", false);

if (getScreenCount() >= 4){

$(".screenshots button[name='addScreen']").attr("disabled", true);

}

if (getScreenCount() <= 1){

$(".screenshots button[name='removeScreen']").attr("disabled", true);

}

}

function getScreenCount() {

return $(".screenshots .inputs :input").length;

}

function addScreenshotField() {

if (getScreenCount() < 4) {

var input =

'<input type="text" ' +

'class="form-control" ' +

'name="screenshot" required>';

$(".screenshots .inputs").append(input);

checkScreenFieldButtons();

}

}

function removeScreenshotField() {

if (getScreenCount() > 1) {

$(".screenshots .inputs input[name='screenshot']").remove();

checkScreenFieldButtons();

}

}

function addGameInput(open) {

if (open === 1){

$("#game .title").slideUp("fast");

$("#game .edit-list").slideUp("fast");

$("#game .game-input").slideDown("fast");

} else {

$("#game .title").slideDown("fast");

$("#game .edit-list").slideDown("fast");

$("#game .game-input").slideUp("fast");

}

}

function productImportBefore() {

$("#admin-product-import .alert").slideUp();

$('#admin-product-import .external-form').attr("disabled", true);

}

function productImportSuccess(responseText) {

console.log(responseText);

$("#admin-product-import .alert").slideDown().html("Добавлено в базу <b>"+responseText+"</b> ключей с сервера поставщика");

$('#admin-product-import .external-form').attr("disabled", false);

}

function productImportError() {

$('#admin-product-import .external-form').attr("disabled", false);

}

function productListBefore() {

$("#admin-product-list .alert").slideUp();

$('#admin-product-list .external-form').attr("disabled", true);

}

function productListSuccess(responseText) {

console.log(responseText);

$("#admin-product-list .alert").slideDown().html("Получено <b>"+responseText.length+"</b> ключей");

$('#admin-product-list .external-form').attr("disabled", false);

}

function productListError() {

$('#admin-product-list .external-form').attr("disabled", false);

}

//STATS

var loadFullStatsAttempts = 0;

var loadShortStatsAttempts = 0;

function loadStats() {

loadShortStats();

loadFullStats();

}

function loadShortStats() {

$.ajax({

type: "POST",

url: "short",

data: "",

success: loadShortStatsSuccess,

error: loadShortStatsError,

dataType: 'json'

});

}

function loadShortStatsSuccess(data) {

$("#all-games .number").html(data['totalGames']);

$("#all-orders .number").html(data['totalOrders']);

$("#all-customers .number").html(data['totalCustomers']);

$("#load-short-stats").slideUp('fast');

$("#short-stats-block").slideDown('fast');

loadShortStatsAttempts = 0;

}

function loadShortStatsError() {

if (loadShortStatsAttempts < 3) {

loadShortStatsAttempts++;

loadShortStats();

}

}

function changeTimeIntervalOnFullStats() {

$("#load-full-stats").slideDown('fast');

$("#full-stats-block").slideUp('fast');

loadFullStats();

}

function loadFullStats() {

var timeInterval = $("#time-interval").val();

$("#time-interval").attr("disabled", true);

$.ajax({

type: "POST",

url: "full",

data: "time-interval="+timeInterval,

success: loadFullStatsSuccess,

error: loadFullStatsError,

dataType: 'json'

});

}

function loadFullStatsSuccess(data) {

$("#orders-count .number").html(data['ordersCount']);

$("#orders-sum .number").html(data['ordersSum']+" ?");

loadFullDataGraphs(data);

console.log(data);

$("#time-interval").attr("disabled", false);

$("#load-full-stats").slideUp('fast');

$("#full-stats-block").slideDown('fast');

loadFullStatsAttempts = 0;

}

function loadFullStatsError() {

if (loadFullStatsAttempts < 3) {

loadFullStatsAttempts++;

loadFullStats();

}

}

function loadFullDataGraphs(data) {

var ctx = $("#ordersGraph");

var myChart = new Chart(ctx, {

type: 'line',

data: {

labels: data["ordersGraph"]["labels"],

datasets: [{

label: 'Заказы',

data: data["ordersGraph"]["data"],

borderWidth: 2,

backgroundColor: 'rgba(255, 255, 255, 0)',

borderColor: '#f47318'

}]

},

options: {

scales: {

yAxes: [{

ticks: {

beginAtZero:true

}

}]

}

}

});

}

Файл: gameshop\src\main\webapp\js\main.js

initialize();

function initialize() {

if ($("#index").length) {

$('#banners-slider').carousel({

interval: 7000

})

}

if ($("#register").length) {

var options = {

beforeSubmit: registerNewCustomerBefore,

success: registerNewCustomerSuccess,

error: registerNewCustomerError,

data_type: 'json'

};

$('#register .register-form').ajaxForm(options);

}

}

function registerNewCustomerBefore(formData, jqForm, options) {

$("#register .register-form .alert").slideUp("fast");

$("#register .register-form button").attr("disabled", "disabled");

$("#register .register-form button").html("Подождите");

}

function registerNewCustomerSuccess(responseText, statusText, xhr, $form) {

$("#register .register-form button").removeAttr("disabled");

$("#register .register-form button").html("Создать аккаунт");

if (responseText.success){

document.location.href="/";

return;

}

formShowValidationErrors($("#register .register-form"), responseText.fieldErrors);

}

function registerNewCustomerError() {

$("#register .register-form .alert").slideDown("fast");

$("#register .register-form button").removeAttr("disabled");

$("#register.register-form button").html("Создать аккаунт");

}

//VALIDATION

function formShowValidationErrors(form, errors) {

form.find('input').tooltip('hide');

form.find('input').removeClass("is-invalid");

for (var k in errors){

if (errors.hasOwnProperty(k)) {

var inputObj = form.find('input[name='+k+']');

inputObj.attr("data-original-title", errors[k]);

inputObj.tooltip('show');

inputObj.addClass("is-invalid");

}

}

}

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\customer\customer.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Список всех покупателей:</h2>

<table class="table">

<thead class="thead-dark">

<tr>

<th>ID</th>

<th>Имя покупателя</th>

<th>Email</th>

<th></th>

</tr>

</thead>

<tbody>

<c:set var="customers" value='${customerDAO.getAll()}' />

<c:forEach items="${customers}" var="customer">

<tr>

<th scope="row">${customer.id}</th>

<td>${customer.name}</td>

<td>${customer.email}</td>

<td class="buttons">

<form class="remove-form" method="post">

<input type="hidden" name="id" value="${customer.id}">

<button type="submit" name="customer-delete" class="btn btn-danger">Удалить</button>

</form>

</td>

</tr>

</c:forEach>

<c:if test="${empty customers}">

<tr>

<th colspan="4" scope="row">ПОКУПАТЕЛЕЙ НЕТ</th>

</tr>

</c:if>

</tbody>

</table>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\game\edit.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<c:set var="editableGame" value='${gameDAO.get(urlParam1)}' scope="request" />

<jsp:include page="/WEB-INF/views/admin/game/game.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\game\game.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<c:set var="games" value='${gameDAO.getAll()}' scope="session" />

<c:set var="pages" value="${gamePaginationService.getPages(games,25)}"/>

<c:set var="totalPages" value="${fn:length(pages)}"/>

<c:choose>

<c:when test="${empty param.p}">

<c:set var="currentPage" value="1"/>

</c:when>

<c:otherwise>

<c:set var="currentPage" value="${param.p}"/>

<c:choose>

<c:when test="${currentPage > fn:length(pages)}">

<c:set var="currentPage" value="${fn:length(pages)}"/>

</c:when>

<c:when test="${currentPage < 1}">

<c:set var="currentPage" value="1"/>

</c:when>

</c:choose>

</c:otherwise>

</c:choose>

<div id="game" class="container">

<c:choose>

<c:when test="${!empty editableGame}">

<div class="row title" style="display: none;">

</c:when>

<c:otherwise>

<div class="row title">

</c:otherwise>

</c:choose>

<div class="col-6">

<h2>Список всех игр:</h2>

</div>

<div class="col-6 add-btn">

<button class="btn btn-primary" type="button" onclick="addGameInput(1)">Добавить игру</button>

</div>

</div>

<c:choose>

<c:when test="${!empty editableGame}">

<div class="row edit-list" style="display: none;">

</c:when>

<c:otherwise>

<div class="row edit-list">

</c:otherwise>

</c:choose>

<div class="col-12">

<table class="table">

<thead class="thead-dark">

<tr>

<th>ID</th>

<th>Title</th>

<th></th>

</tr>

</thead>

<tbody>

<c:choose>

<c:when test="${!empty games}">

<c:forEach items="${pages.get(currentPage-1)}" var="game">

<tr>

<th scope="row">${game.id}</th>

<td>${game.title}</td>

<td class="buttons">

<a class="btn btn-warning" href="/admin/game/edit/${game.id}">Редактировать</a>

<form class="remove-form" method="post" action="/admin/game/remove">

<input type="hidden" name="id" value="${game.id}">

<button type="submit" name="game-delete" class="btn btn-danger">Удалить</button>

</form>

</td>

</tr>

</c:forEach>

</c:when>

<c:otherwise>

<tr>

<th colspan="3" scope="row"><% out.print("ИГР НЕТ"); %></th>

</tr>

</c:otherwise>

</c:choose>

</tbody>

</table>

<c:set var="pagesAround" value="2"/>

<c:if test="${totalPages>1}">

<div class="pages">

<div class="pager">

<ul class="pagination">

<c:if test="${(currentPage - pagesAround)>1}">

<li class="page-item">

<a class="page-link" href="?p=1">Первая</a>

</li>

</c:if>

<c:if test="${currentPage>1}">

<li class="page-item">

<a class="page-link" href="?p=${currentPage-1}">&laquo;</a>

</li>

</c:if>

<c:forEach begin="1" end="${totalPages}" varStatus="loop">

<c:choose>

<c:when test="${(loop.index >= (currentPage-pagesAround)) && (loop.index <= (currentPage+pagesAround))}">

<li class="page-item <c:if test="${currentPage == loop.index}">active</c:if>">

<a class="page-link" href="?p=${loop.index}">${loop.index}</a>

</li>

</c:when>

<c:when test="${((currentPage+pagesAround) - loop.index) == 0}">

<li class="page-item <c:if test="${currentPage == loop.index}">active</c:if>">

<a class="page-link" href="?p=${loop.index}">${loop.index}</a>

</li>

</c:when>

</c:choose>

</c:forEach>

<c:if test="${currentPage<totalPages}">

<li class="page-item">

<a class="page-link" href="?p=${currentPage+1}">&raquo;</a>

</li>

</c:if>

<c:if test="${(currentPage + pagesAround)<totalPages}">

<li class="page-item">

<a class="page-link" href="?p=${totalPages}">Последняя</a>

</li>

</c:if>

</ul>

</div>

</div>

</c:if>

</div>

</div>

<c:choose>

<c:when test="${!empty editableGame}">

<div class="row game-input">

</c:when>

<c:otherwise>

<div class="row game-input" style="display: none;">

</c:otherwise>

</c:choose>

<div class="col-12">

<c:choose>

<c:when test="${!empty editableGame}">

<h2>Редактирование игры:</h2>

</c:when>

<c:otherwise>

<h2>Добавить игру:</h2>

</c:otherwise>

</c:choose>

<form method="post">

<c:if test="${!empty editableGame}">

<input type="hidden" name="id" value="${editableGame.id}">

</c:if>

<div class="form-group">

<label>Название: </label>

<input type="text" class="form-control" name="title" value="${editableGame.title}" required>

</div>

<div class="form-group">

<label>Описание: </label>

<textarea class="form-control" name="description" rows="6" required>${editableGame.description}</textarea>

</div>

<c:set var="languages" value='${languageDAO.getAll()}' />

<div class="form-group">

<label>Поддерживаемые языки: </label>

<select multiple class="form-control" name="languages" required>

<c:forEach items="${languages}" var="language">

<c:set var="finded" value="0" scope="page"/>

<c:forEach items="${editableGame.languages}" var="t">

<c:if test="${t.id == language.id}">

<c:set var="finded" value="1"/>

</c:if>

</c:forEach>

<option

<c:if test="${finded == 1}">selected</c:if>

value="${language.id}">${language.name}</option>

</c:forEach>

</select>

</div>

<c:set var="platforms" value='${platformDAO.getAll()}' />

<div class="form-group">

<label>Поддерживаемые платформы: </label>

<select multiple class="form-control" name="platforms" required>

<c:forEach items="${platforms}" var="platform">

<c:set var="finded" value="0" scope="page"/>

<c:forEach items="${editableGame.platforms}" var="t">

<c:if test="${t.id == platform.id}">

<c:set var="finded" value="1"/>

</c:if>

</c:forEach>

<option

<c:if test="${finded == 1}">selected</c:if>

value="${platform.id}">${platform.name}</option>

</c:forEach>

</select>

</div>

<c:set var="genres" value='${genreDAO.getAll()}' />

<div class="form-group">

<label>Жанры: </label>

<select multiple class="form-control" name="genres" required>

<c:forEach items="${genres}" var="genre">

<c:set var="finded" value="0" scope="page"/>

<c:forEach items="${editableGame.genres}" var="t">

<c:if test="${t.id == genre.id}">

<c:set var="finded" value="1"/>

</c:if>

</c:forEach>

<option

<c:if test="${finded == 1}">selected</c:if>

value="${genre.id}">${genre.name}</option>

</c:forEach>

</select>

</div>

<div class="form-group">

<label>Разработчик: </label>

<input type="text" class="form-control" name="developer" value="${editableGame.developer}" required>

</div>

<div class="form-group">

<label>Дата релиза игры: </label>

<input type="date" class="form-control" name="release-date" value="${editableGame.releaseDate}" required>

</div>

<div class="form-group">

<label>Ссылка на постер: </label>

<input type="text" class="form-control" name="poster-image-url" value="${editableGame.posterImageUrl}" required>

</div>

<div class="form-group screenshots">

<label>Сслыки на скриншоты: </label>

<c:choose>

<c:when test="${!empty editableGame}">

<c:set var="i" value="1" scope="page"/>

<div class="inputs">

<c:forEach items="${editableGame.screenshotsUrls}" var="screenshot">

<input type="text" class="form-control" name="screenshot" value="${screenshot}" required>

<c:set var="i" value="${i + 1}" scope="page"/>

</c:forEach>

</div>

</c:when>

<c:otherwise>

<div class="inputs">

<input type="text" class="form-control" name="screenshot" required>

</div>

</c:otherwise>

</c:choose>

<button type="button" name="addScreen" class="btn btn-primary btn-sm" onclick="addScreenshotField()">Добавить поле</button>

<button type="button" name="removeScreen" class="btn btn-danger btn-sm" disabled onclick="removeScreenshotField()">Удалить поле</button>

</div>

<div class="form-group">

<label>Цена игры: </label>

<input type="number" min="0" class="form-control" name="price" value="${editableGame.price}" required>

</div>

<c:choose>

<c:when test="${!empty editableGame}">

<button type="submit" name="game-edit-submit" class="btn btn-primary">Завершить редактирование</button>

<a class="btn btn-secondary" href="/admin/game/">Назад</a>

</c:when>

<c:otherwise>

<button type="submit" name="game-add-submit" class="btn btn-primary">Добавить игру</button>

<button class="btn btn-secondary" type="button" onclick="addGameInput(0)">Закрыть</button>

</c:otherwise>

</c:choose>

</form>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\genre\edit.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<c:set var="genre" value='${genreDAO.get(urlParam1)}' />

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Редактирование жанра:</h2>

<form method="post">

<input type="hidden" name="id" value="${genre.id}">

<div class="form-group">

<label>Название: </label>

<input type="text" class="form-control" name="name" value="${genre.name}" required>

</div>

<button type="submit" name="genre-edit-submit" class="btn btn-primary">Завершить редактирование</button>

<a class="btn btn-secondary" href="/admin/genre/">Назад</a>

</form>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\genre\genre.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Список всех жанров:</h2>

<table class="table">

<thead class="thead-dark">

<tr>

<th>ID</th>

<th>Название</th>

<th></th>

</tr>

</thead>

<tbody>

<c:set var="genres" value='${genreDAO.getAll()}' />

<c:forEach items="${genres}" var="genre">

<tr>

<th scope="row">${genre.id}</th>

<td>${genre.name}</td>

<td class="buttons">

<a class="btn btn-warning" href="/admin/genre/edit/${genre.id}">Редактировать</a>

<form class="remove-form" method="post" action="/admin/genre/remove">

<input type="hidden" name="id" value="${genre.id}">

<button type="submit" name="genre-delete" class="btn btn-danger">Удалить</button>

</form>

</td>

</tr>

</c:forEach>

<c:if test="${empty genres}">

<tr>

<th colspan="3" scope="row"><% out.print("ПОКА НИЧЕГО НЕ ЗАПОЛНЕНО"); %></th>

</tr>

</c:if>

</tbody>

</table>

</div>

</div>

<div class="row edit-list">

<div class="col-12">

<h2>Добавить жанр:</h2>

<form method="post">

<div class="form-group">

<label>Название: </label>

<input type="text" class="form-control" name="name" required>

</div>

<button type="submit" name="genre-add-submit" class="btn btn-primary">Добавить жанр</button>

</form>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\language\edit.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<c:set var="language" value='${languageDAO.get(urlParam1)}' />

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Редактирование языка:</h2>

<form method="post">

<input type="hidden" name="id" value="${language.id}">

<div class="form-group">

<label>Название: </label>

<input type="text" class="form-control" name="name" value="${language.name}" required>

</div>

<button type="submit" name="language-edit-submit" class="btn btn-primary">Завершить редактирование</button>

<a class="btn btn-secondary" href="/admin/language/">Назад</a>

</form>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\language\language.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Список всех языков:</h2>

<table class="table">

<thead class="thead-dark">

<tr>

<th>ID</th>

<th>Название</th>

<th></th>

</tr>

</thead>

<tbody>

<c:set var="languages" value='${languageDAO.getAll()}' />

<c:forEach items="${languages}" var="language">

<tr>

<th scope="row">${language.id}</th>

<td>${language.name}</td>

<td class="buttons">

<a class="btn btn-warning" href="/admin/language/edit/${language.id}">Редактировать</a>

<form class="remove-form" method="post" action="/admin/language/remove">

<input type="hidden" name="id" value="${language.id}">

<button type="submit" name="language-delete" class="btn btn-danger">Удалить</button>

</form>

</td>

</tr>

</c:forEach>

<c:if test="${empty languages}">

<tr>

<th colspan="3" scope="row"><% out.print("ПОКА НИЧЕГО НЕ ЗАПОЛНЕНО"); %></th>

</tr>

</c:if>

</tbody>

</table>

</div>

</div>

<div class="row edit-list">

<div class="col-12">

<h2>Добавить язык:</h2>

<form method="post">

<div class="form-group">

<label>Название: </label>

<input type="text" class="form-control" name="name" required>

</div>

<button type="submit" name="language-add-submit" class="btn btn-primary">Добавить язык</button>

</form>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\order\order.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/header.jsp"/>

<div class="container">

<div class="row edit-list">

<div class="col-12">

<h2>Список всех заказов:</h2>

<table class="table">

<thead class="thead-dark">

<tr>

<th>ID</th>

<th>Дата</th>

<th>Имя покупателя</th>

<th>Игры в заказе</th>

<th></th>

</tr>

</thead>

<tbody>

<c:set var="orders" value='${orderDAO.getAll()}' />

<c:forEach items="${orders}" var="order">

<tr>

<th scope="row">${order.id}</th>

<td>${order.date}</td>

<td>${order.customer.name}</td>

<td>

<c:forEach items="${order.products}" var="product">

${product.game.title}<br>

</c:forEach>

</td>

<td class="buttons">

<form class="remove-form" method="post">

<input type="hidden" name="id" value="${order.id}">

<button type="submit" name="order-delete" class="btn btn-danger">Удалить</button>

</form>

</td>

</tr>

</c:forEach>

<c:if test="${empty orders}">

<tr>

<th colspan="5" scope="row">ЗАКАЗОВ НЕТ</th>

</tr>

</c:if>

</tbody>

</table>

</div>

</div>

</div>

<jsp:include page="/WEB-INF/views/admin/parts/footer.jsp"/>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\parts\footer.jsp

<script type='text/javascript' src='/js/jquery.min.js'></script>

<script type='text/javascript' src='/js/jquery.form.min.js'></script>

<script type='text/javascript' src='/js/popper.min.js'></script>

<script type='text/javascript' src='/js/bootstrap.min.js'></script>

<script type='text/javascript' src='/js/chart.min.js'></script>

<script type='text/javascript' src='/js/admin.js'></script>

</body>

</html>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\parts\head-includes.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

<meta itemprop="image" content="/images/icon.png" />

<link rel="icon" href="/images/icon.png" sizes="32x32" />

<link rel="icon" href="/images/icon.png" sizes="192x192" />

<link rel="apple-touch-icon-precomposed" href="/images/icon.png" />

<meta name="msapplication-TileImage" content="/images/icon.png" />

<meta name="viewport" content="width=device-width">

<meta charset="utf-8">

<title>Панель управления</title>

<link rel="stylesheet" href="/css/bootstrap.min.css">

<link rel="stylesheet" href="/css/style.css">

</head>

Файл: gameshop\src\main\webapp\WEB-INF\views\admin\parts\header.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<jsp:include page="/WEB-INF/views/admin/parts/head-includes.jsp"/>

<body id="admin">

<header>

<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">

<a class="navbar-brand" href="/admin/">ПАНЕЛЬ УПРАВЛЕНИЯ</a>

<button class="nav...


Подобные документы

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.