You've already forked AdminPanel
mirror of
https://github.com/akpaevj/AdminPanel.git
synced 2026-04-24 19:03:51 +02:00
Добавьте файлы проекта.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30114.105
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdminPanel", "AdminPanel\AdminPanel.csproj", "{A9EEE8E0-9044-45B7-8EA7-42FD79E16C0A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A9EEE8E0-9044-45B7-8EA7-42FD79E16C0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A9EEE8E0-9044-45B7-8EA7-42FD79E16C0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A9EEE8E0-9044-45B7-8EA7-42FD79E16C0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A9EEE8E0-9044-45B7-8EA7-42FD79E16C0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F9D2BF9A-A8AF-455C-A63C-6F4E46E51B65}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "3.1.4",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
using AdminPanel.Models;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel
|
||||
{
|
||||
public class AppDbContext : DbContext
|
||||
{
|
||||
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
|
||||
=> Database.EnsureCreated();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<InfoBaseInfoBasesList>()
|
||||
.HasKey(c => new { c.InfoBaseId, c.InfoBasesListId });
|
||||
}
|
||||
|
||||
public void ManyToMany<T>(List<T> newCollection, List<T> oldCollection)
|
||||
{
|
||||
newCollection
|
||||
.Except(oldCollection)
|
||||
.ToList()
|
||||
.ForEach(x => newCollection.Remove(x));
|
||||
|
||||
oldCollection
|
||||
.Except(newCollection)
|
||||
.ToList()
|
||||
.ForEach(x => newCollection.Add(x));
|
||||
}
|
||||
|
||||
public DbSet<User> Users { get; set; }
|
||||
public DbSet<InfoBase> InfoBases { get; set; }
|
||||
public DbSet<InfoBasesList> InfoBasesLists { get; set; }
|
||||
public DbSet<InfoBaseInfoBasesList> InfoBaseInfoBasesLists { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using AdminPanel.Models;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
public class ErrorController : Controller
|
||||
{
|
||||
private readonly ILogger<ErrorController> _logger;
|
||||
|
||||
public ErrorController(ILogger<ErrorController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[Route("/error")]
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
var exceptionHandlerPathFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();
|
||||
|
||||
var viewModel = new ErrorViewModel
|
||||
{
|
||||
Title = "Ошибка",
|
||||
Details = exceptionHandlerPathFeature.Error.Message
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AdminPanel;
|
||||
using AdminPanel.Models;
|
||||
using AutoMapper;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
[Authorize(Policy = "OnlyAdmins")]
|
||||
public class InfoBasesController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InfoBasesController(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
// GET: InfoBases
|
||||
public async Task<IActionResult> Index(int page = 1)
|
||||
{
|
||||
const int pageSize = 100;
|
||||
|
||||
var source = _context.InfoBases;
|
||||
var count = await source.CountAsync();
|
||||
var pagesAmount = (int)Math.Ceiling((double)count / pageSize);
|
||||
|
||||
var viewModel = new InfoBaseIndexViewModel
|
||||
{
|
||||
Items = await source
|
||||
.OrderBy(c => c.Name)
|
||||
.Skip((pageSize * (page - 1)))
|
||||
.Take(pageSize)
|
||||
.ProjectTo<InfoBaseViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync(),
|
||||
CurrentPage = page,
|
||||
PagesAmount = pagesAmount
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBases/Create
|
||||
public async Task<IActionResult> Create()
|
||||
{
|
||||
var viewModel = new InfoBaseViewModel();
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: InfoBases/Create
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to, for
|
||||
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Create(InfoBaseViewModel viewModel, Guid[] selectedInfoBasesLists)
|
||||
{
|
||||
EditModelStateForConnectionType(viewModel, ModelState);
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var infoBase = _mapper.Map<InfoBase>(viewModel);
|
||||
infoBase.Id = Guid.NewGuid();
|
||||
infoBase.SetIBasesContent();
|
||||
|
||||
await UpdateInfoBasesListsAsync(infoBase, selectedInfoBasesLists);
|
||||
|
||||
_context.Add(infoBase);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBases/Edit/5
|
||||
public async Task<IActionResult> Edit(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var viewModel = await _context.InfoBases.ProjectTo<InfoBaseViewModel>(_mapper.ConfigurationProvider).FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
if (viewModel == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: InfoBases/Edit/5
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to, for
|
||||
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Edit(Guid id, InfoBaseViewModel viewModel, Guid[] selectedInfoBasesLists)
|
||||
{
|
||||
if (id != viewModel.Id)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
EditModelStateForConnectionType(viewModel, ModelState);
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var infoBase = _mapper.Map<InfoBase>(viewModel);
|
||||
var infoBaseToUpdate = await _context.InfoBases
|
||||
.Include(c => c.InfoBaseInfoBasesLists)
|
||||
.ThenInclude(c => c.InfoBasesList)
|
||||
.FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
_mapper.Map(infoBase, infoBaseToUpdate);
|
||||
|
||||
infoBaseToUpdate.SetIBasesContent();
|
||||
|
||||
try
|
||||
{
|
||||
await UpdateInfoBasesListsAsync(infoBaseToUpdate, selectedInfoBasesLists);
|
||||
|
||||
_context.Update(infoBaseToUpdate);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!InfoBaseExists(infoBaseToUpdate.Id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBases/Delete/5
|
||||
public async Task<IActionResult> Delete(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var infoBase = await _context.InfoBases
|
||||
.ProjectTo<InfoBaseViewModel>(_mapper.ConfigurationProvider)
|
||||
.FirstOrDefaultAsync(m => m.Id == id);
|
||||
|
||||
if (infoBase == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(infoBase);
|
||||
}
|
||||
|
||||
// POST: InfoBases/Delete/5
|
||||
[HttpPost, ActionName("Delete")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DeleteConfirmed(Guid id)
|
||||
{
|
||||
var infoBase = await _context.InfoBases.FindAsync(id);
|
||||
_context.InfoBases.Remove(infoBase);
|
||||
await _context.SaveChangesAsync();
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
private bool InfoBaseExists(Guid id)
|
||||
{
|
||||
return _context.InfoBases.Any(e => e.Id == id);
|
||||
}
|
||||
|
||||
private async Task PopulateViewBagData(Guid? Id)
|
||||
{
|
||||
var selectedInfoBasesLists = new List<InfoBaseInfoBasesList>();
|
||||
|
||||
if (Id != null)
|
||||
selectedInfoBasesLists = await _context.InfoBaseInfoBasesLists
|
||||
.Where(c => c.InfoBaseId == Id)
|
||||
.Include(c => c.InfoBasesList)
|
||||
.ToListAsync();
|
||||
|
||||
PopulateInfoBasesLists(selectedInfoBasesLists);
|
||||
|
||||
await PopulateAllInfoBasesListsAsync(selectedInfoBasesLists);
|
||||
}
|
||||
private void PopulateInfoBasesLists(IEnumerable<InfoBaseInfoBasesList> selectedInfoBasesLists)
|
||||
{
|
||||
ViewBag.SelectedInfoBasesLists = selectedInfoBasesLists.Select(c => (Id: c.InfoBasesListId, c.InfoBasesList.Name)).ToList();
|
||||
}
|
||||
private async Task PopulateAllInfoBasesListsAsync(IEnumerable<InfoBaseInfoBasesList> selectedInfoBasesLists)
|
||||
{
|
||||
var exceptions = selectedInfoBasesLists.Select(c => c.InfoBasesListId).ToList();
|
||||
|
||||
var data = await _context.InfoBasesLists
|
||||
.OrderBy(c => c.Name)
|
||||
.Select(c => new { c.Id, c.Name })
|
||||
.ToListAsync();
|
||||
|
||||
data.RemoveAll(c => exceptions.Contains(c.Id));
|
||||
|
||||
ViewBag.AllInfoBasesLists = new SelectList(data, "Id", "Name");
|
||||
}
|
||||
private async Task UpdateInfoBasesListsAsync(InfoBase infoBaseToUpdate, Guid[] selectedInfoBasesLists)
|
||||
{
|
||||
if (selectedInfoBasesLists == null)
|
||||
return;
|
||||
|
||||
// Удалим не выбранные позиции
|
||||
for (int i = 0; i < infoBaseToUpdate.InfoBaseInfoBasesLists.Count; i++)
|
||||
{
|
||||
var item = infoBaseToUpdate.InfoBaseInfoBasesLists[i];
|
||||
|
||||
if (!selectedInfoBasesLists.Contains(item.InfoBasesListId))
|
||||
{
|
||||
UpdateInfoBasesListId(item.InfoBasesList);
|
||||
|
||||
infoBaseToUpdate.InfoBaseInfoBasesLists.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавим новые позиции и обновим
|
||||
foreach (var selectedId in selectedInfoBasesLists)
|
||||
{
|
||||
var infoBaseInfoBasesList = infoBaseToUpdate.InfoBaseInfoBasesLists.FirstOrDefault(c => c.InfoBasesListId == selectedId);
|
||||
|
||||
if (infoBaseInfoBasesList == null)
|
||||
{
|
||||
var infoBasesList = await _context.InfoBasesLists.FindAsync(selectedId);
|
||||
|
||||
infoBaseInfoBasesList = new InfoBaseInfoBasesList()
|
||||
{
|
||||
InfoBasesList = infoBasesList,
|
||||
InfoBasesListId = selectedId
|
||||
};
|
||||
|
||||
infoBaseToUpdate.InfoBaseInfoBasesLists.Add(infoBaseInfoBasesList);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновим внутренние GUID списков для корректной работы веб-сервиса
|
||||
foreach (var item in infoBaseToUpdate.InfoBaseInfoBasesLists)
|
||||
{
|
||||
UpdateInfoBasesListId(item.InfoBasesList);
|
||||
}
|
||||
}
|
||||
private void UpdateInfoBasesListId(InfoBasesList infoBasesList)
|
||||
{
|
||||
infoBasesList.ListId = Guid.NewGuid();
|
||||
|
||||
_context.Entry(infoBasesList).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
private void EditModelStateForConnectionType(InfoBaseViewModel viewModel, ModelStateDictionary modelState)
|
||||
{
|
||||
if (viewModel.ConnectionType == InfoBaseConnectionType.File)
|
||||
{
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.URL));
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.Server));
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.InfoBaseName));
|
||||
}
|
||||
else if (viewModel.ConnectionType == InfoBaseConnectionType.Server)
|
||||
{
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.URL));
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.Path));
|
||||
}
|
||||
else if (viewModel.ConnectionType == InfoBaseConnectionType.WebServer)
|
||||
{
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.Path));
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.Server));
|
||||
ModelState.Remove(nameof(InfoBaseViewModel.InfoBaseName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AdminPanel;
|
||||
using AdminPanel.Models;
|
||||
using AutoMapper;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using AdminPanel.ViewModels.Users;
|
||||
using AutoMapper.EntityFrameworkCore;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
[Authorize(Policy = "OnlyAdmins")]
|
||||
public class InfoBasesListsController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public InfoBasesListsController(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
// GET: InfoBasesLists
|
||||
public async Task<IActionResult> Index(int page = 1)
|
||||
{
|
||||
const int pageSize = 100;
|
||||
|
||||
var source = _context.InfoBasesLists;
|
||||
var count = await source.CountAsync();
|
||||
var pagesAmount = (int)Math.Ceiling((double)count / pageSize);
|
||||
|
||||
var viewModel = new InfoBasesListIndexViewModel
|
||||
{
|
||||
Items = await source
|
||||
.OrderBy(c => c.Name)
|
||||
.Skip((pageSize * (page - 1)))
|
||||
.Take(pageSize)
|
||||
.ProjectTo<InfoBasesListViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync(),
|
||||
CurrentPage = page,
|
||||
PagesAmount = pagesAmount
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBasesLists/Create
|
||||
public async Task<IActionResult> Create()
|
||||
{
|
||||
var viewModel = new InfoBasesListViewModel();
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: InfoBasesLists/Create
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to, for
|
||||
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Create(InfoBasesListViewModel viewModel, Guid[] selectedInfoBases, Guid[] selectedUsers)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var infoBasesList = _mapper.Map<InfoBasesList>(viewModel);
|
||||
|
||||
infoBasesList.Id = Guid.NewGuid();
|
||||
infoBasesList.ListId = Guid.NewGuid();
|
||||
|
||||
await UpdateInfoBasesAsync(infoBasesList, selectedInfoBases);
|
||||
await UpdateUsersAsync(infoBasesList, selectedUsers);
|
||||
|
||||
_context.Add(infoBasesList);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
await PopulateViewBagData(viewModel.Id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBasesLists/Edit/5
|
||||
public async Task<IActionResult> Edit(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var viewModel = await _context.InfoBasesLists.ProjectTo<InfoBasesListViewModel>(_mapper.ConfigurationProvider).FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
if (viewModel == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
await PopulateViewBagData(id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: InfoBasesLists/Edit/5
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to, for
|
||||
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Edit(Guid id, InfoBasesListViewModel viewModel, Guid[] selectedInfoBases, Guid[] selectedUsers)
|
||||
{
|
||||
if (id != viewModel.Id)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var infoBasesList = _mapper.Map<InfoBasesList>(viewModel);
|
||||
infoBasesList.ListId = Guid.NewGuid();
|
||||
|
||||
var infoBasesListToUpdate = await _context.InfoBasesLists
|
||||
.Include(c => c.InfoBaseInfoBasesLists)
|
||||
.ThenInclude(c => c.InfoBase)
|
||||
.Include(c => c.Users)
|
||||
.FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
_mapper.Map(infoBasesList, infoBasesListToUpdate);
|
||||
|
||||
try
|
||||
{
|
||||
await UpdateInfoBasesAsync(infoBasesListToUpdate, selectedInfoBases);
|
||||
await UpdateUsersAsync(infoBasesListToUpdate, selectedUsers);
|
||||
|
||||
_context.Update(infoBasesListToUpdate);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!InfoBasesListExists(infoBasesListToUpdate.Id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
await PopulateViewBagData(id);
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: InfoBasesLists/Delete/5
|
||||
public async Task<IActionResult> Delete(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var infoBasesList = await _context.InfoBasesLists
|
||||
.ProjectTo<InfoBasesListViewModel>(_mapper.ConfigurationProvider)
|
||||
.FirstOrDefaultAsync(m => m.Id == id);
|
||||
|
||||
if (infoBasesList == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(infoBasesList);
|
||||
}
|
||||
|
||||
// POST: InfoBasesLists/Delete/5
|
||||
[HttpPost, ActionName("Delete")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DeleteConfirmed(Guid id)
|
||||
{
|
||||
var infoBasesList = await _context.InfoBasesLists.FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
await ClearUsersInfoBasesListAsync(id);
|
||||
|
||||
_context.InfoBasesLists.Remove(infoBasesList);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
private bool InfoBasesListExists(Guid id)
|
||||
{
|
||||
return _context.InfoBasesLists.Any(e => e.Id == id);
|
||||
}
|
||||
|
||||
private async Task PopulateViewBagData(Guid? Id)
|
||||
{
|
||||
// Списки информационных баз
|
||||
var selectedInfoBases = new List<InfoBaseInfoBasesList>();
|
||||
|
||||
if (Id != null)
|
||||
selectedInfoBases = await _context.InfoBaseInfoBasesLists
|
||||
.Where(c => c.InfoBasesListId == Id)
|
||||
.Include(c => c.InfoBase)
|
||||
.ToListAsync();
|
||||
|
||||
PopulateInfoBases(selectedInfoBases);
|
||||
|
||||
await PopulateAllInfoBasesAsync(selectedInfoBases);
|
||||
|
||||
// Списки пользователей
|
||||
var selectedUsers = new List<User>();
|
||||
|
||||
if (Id != null)
|
||||
selectedUsers = await _context.Users
|
||||
.Where(c => c.InfoBasesListId == Id)
|
||||
.ToListAsync();
|
||||
|
||||
PopulateUsers(selectedUsers);
|
||||
|
||||
await PopulateAllUsersAsync(selectedUsers);
|
||||
}
|
||||
private void PopulateInfoBases(IEnumerable<InfoBaseInfoBasesList> selectedInfoBases)
|
||||
{
|
||||
ViewBag.SelectedInfoBases = selectedInfoBases.Select(c => (Id: c.InfoBaseId, c.InfoBase.Name)).ToList();
|
||||
}
|
||||
private void PopulateUsers(IEnumerable<User> selectedUsers)
|
||||
{
|
||||
ViewBag.SelectedUsers = selectedUsers.Select(c => (c.Id, c.Name)).ToList();
|
||||
}
|
||||
private async Task PopulateAllInfoBasesAsync(IEnumerable<InfoBaseInfoBasesList> selectedInfoBases)
|
||||
{
|
||||
var exceptions = selectedInfoBases.Select(c => c.InfoBaseId).ToList();
|
||||
|
||||
var data = await _context.InfoBases
|
||||
.OrderBy(c => c.Name)
|
||||
.Select(c => new { c.Id, c.Name })
|
||||
.ToListAsync();
|
||||
|
||||
data.RemoveAll(c => exceptions.Contains(c.Id));
|
||||
|
||||
ViewBag.AllInfoBases = new SelectList(data, "Id", "Name");
|
||||
}
|
||||
private async Task PopulateAllUsersAsync(IEnumerable<User> selectedUsers)
|
||||
{
|
||||
var exceptions = selectedUsers.Select(c => c.Id).ToList();
|
||||
|
||||
var data = await _context.Users
|
||||
.Where(c => c.InfoBasesListId == null)
|
||||
.OrderBy(c => c.Name)
|
||||
.Select(c => new { c.Id, c.Name })
|
||||
.ToListAsync();
|
||||
|
||||
data.RemoveAll(c => exceptions.Contains(c.Id));
|
||||
|
||||
ViewBag.AllUsers = new SelectList(data, "Id", "Name");
|
||||
}
|
||||
private async Task UpdateInfoBasesAsync(InfoBasesList infoBaseListToUpdate, Guid[] selectedInfoBases)
|
||||
{
|
||||
if (selectedInfoBases == null)
|
||||
return;
|
||||
|
||||
// Удалим не выбранные позиции
|
||||
for (int i = 0; i < infoBaseListToUpdate.InfoBaseInfoBasesLists.Count; i++)
|
||||
{
|
||||
var item = infoBaseListToUpdate.InfoBaseInfoBasesLists[i];
|
||||
|
||||
if (!selectedInfoBases.Contains(item.InfoBaseId))
|
||||
{
|
||||
infoBaseListToUpdate.InfoBaseInfoBasesLists.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавим новые позиции и обновим
|
||||
foreach (var selectedId in selectedInfoBases)
|
||||
{
|
||||
var infoBaseInfoBasesList = infoBaseListToUpdate.InfoBaseInfoBasesLists.FirstOrDefault(c => c.InfoBaseId == selectedId);
|
||||
|
||||
if (infoBaseInfoBasesList == null)
|
||||
{
|
||||
var infoBase = await _context.InfoBases.FindAsync(selectedId);
|
||||
|
||||
infoBaseInfoBasesList = new InfoBaseInfoBasesList()
|
||||
{
|
||||
InfoBase = infoBase,
|
||||
InfoBaseId = selectedId
|
||||
};
|
||||
|
||||
infoBaseListToUpdate.InfoBaseInfoBasesLists.Add(infoBaseInfoBasesList);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task UpdateUsersAsync(InfoBasesList infoBaseListToUpdate, Guid[] selectedUsers)
|
||||
{
|
||||
if (selectedUsers == null)
|
||||
return;
|
||||
|
||||
// Удалим не выбранные позиции
|
||||
for (int i = 0; i < infoBaseListToUpdate.Users.Count; i++)
|
||||
{
|
||||
var item = infoBaseListToUpdate.Users[i];
|
||||
|
||||
if (!selectedUsers.Contains(item.Id))
|
||||
{
|
||||
infoBaseListToUpdate.Users.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Добавим новые позиции и обновим
|
||||
foreach (var selectedId in selectedUsers)
|
||||
{
|
||||
var user = infoBaseListToUpdate.Users.FirstOrDefault(c => c.Id == selectedId);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
user = await _context.Users.FindAsync(selectedId);
|
||||
|
||||
infoBaseListToUpdate.Users.Add(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
private async Task ClearUsersInfoBasesListAsync(Guid infoBasesListId)
|
||||
{
|
||||
var users = await _context.Users.Where(c => c.InfoBasesListId == infoBasesListId).ToListAsync();
|
||||
|
||||
foreach (var item in users)
|
||||
{
|
||||
item.InfoBasesListId = null;
|
||||
item.InfoBasesList = null;
|
||||
}
|
||||
|
||||
_context.UpdateRange(users);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using AdminPanel;
|
||||
using AdminPanel.Models;
|
||||
using AutoMapper;
|
||||
using AdminPanel.ViewModels.Users;
|
||||
using AutoMapper.QueryableExtensions;
|
||||
using System.DirectoryServices.AccountManagement;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.DirectoryServices;
|
||||
using System.Text;
|
||||
using System.Security.Principal;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
[Authorize(Policy = "OnlyAdmins")]
|
||||
public class UsersController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public UsersController(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
// GET: Users
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
// GET: Users/Edit/5
|
||||
public async Task<IActionResult> Edit(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var viewModel = await _context.Users
|
||||
.ProjectTo<UserViewModel>(_mapper.ConfigurationProvider)
|
||||
.FirstOrDefaultAsync(c => c.Id == id);
|
||||
|
||||
if (viewModel == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
await PopulateViewBagData();
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: Users/Edit/5
|
||||
// To protect from overposting attacks, enable the specific properties you want to bind to, for
|
||||
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Edit(Guid id, UserViewModel viewModel)
|
||||
{
|
||||
if (id != viewModel.Id)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (viewModel.InfoBasesListId == Guid.Empty)
|
||||
viewModel.InfoBasesListId = null;
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = _mapper.Map<User>(viewModel);
|
||||
user.InfoBasesList = null;
|
||||
|
||||
try
|
||||
{
|
||||
_context.Update(user);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!UserExists(user.Id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
await PopulateViewBagData();
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: Users/Delete/5
|
||||
public async Task<IActionResult> Delete(Guid? id)
|
||||
{
|
||||
if (id == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var viewModel = await _context.Users
|
||||
.ProjectTo<UserViewModel>(_mapper.ConfigurationProvider).FirstOrDefaultAsync(m => m.Id == id);
|
||||
if (viewModel == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: Users/Delete/5
|
||||
[HttpPost, ActionName("Delete")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DeleteConfirmed(Guid id)
|
||||
{
|
||||
var user = await _context.Users.FindAsync(id);
|
||||
_context.Users.Remove(user);
|
||||
await _context.SaveChangesAsync();
|
||||
return RedirectToAction(nameof(Index));
|
||||
}
|
||||
|
||||
private bool UserExists(Guid id)
|
||||
{
|
||||
return _context.Users.Any(e => e.Id == id);
|
||||
}
|
||||
|
||||
private bool UserExists(string sid)
|
||||
{
|
||||
return _context.Users.Any(e => e.Sid == sid);
|
||||
}
|
||||
|
||||
private async Task<User> GetUserAsync(string sid)
|
||||
{
|
||||
return await _context.Users.FirstOrDefaultAsync(c => c.Sid == sid);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> UpdateFromActiveDirectory()
|
||||
{
|
||||
var listToAdd = new List<User>();
|
||||
var listToUpdate = new List<User>();
|
||||
|
||||
var entry = Domain.GetCurrentDomain().GetDirectoryEntry();
|
||||
|
||||
var searcher = new DirectorySearcher(entry, "(&(objectCategory=person)(objectclass=user))");
|
||||
searcher.PropertiesToLoad.Add("name");
|
||||
searcher.PropertiesToLoad.Add("samAccountName");
|
||||
searcher.PropertiesToLoad.Add("objectSID");
|
||||
|
||||
var result = searcher.FindAll();
|
||||
|
||||
foreach (SearchResult searchResult in result)
|
||||
{
|
||||
var sid = GetPropertyValue(searchResult, "objectSID");
|
||||
|
||||
if (!UserExists(sid))
|
||||
{
|
||||
var user = new User
|
||||
{
|
||||
Name = GetPropertyValue(searchResult, "name"),
|
||||
Sid = sid,
|
||||
SamAccountName = GetPropertyValue(searchResult, "samAccountName")
|
||||
};
|
||||
|
||||
listToAdd.Add(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
var existsUser = await GetUserAsync(sid);
|
||||
|
||||
var user = new User
|
||||
{
|
||||
Name = GetPropertyValue(searchResult, "name"),
|
||||
Sid = sid,
|
||||
SamAccountName = GetPropertyValue(searchResult, "samAccountName")
|
||||
};
|
||||
|
||||
if (!existsUser.Equals(user))
|
||||
{
|
||||
existsUser.Name = user.Name;
|
||||
existsUser.SamAccountName = user.SamAccountName;
|
||||
existsUser.Sid = user.Sid;
|
||||
|
||||
listToUpdate.Add(existsUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await _context.Users.AddRangeAsync(listToAdd);
|
||||
_context.Users.UpdateRange(listToUpdate);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
private string GetPropertyValue(SearchResult result, string propertyName)
|
||||
{
|
||||
if (result.Properties.Contains(propertyName))
|
||||
{
|
||||
var value = result.Properties[propertyName]?[0];
|
||||
|
||||
if (value.GetType() == typeof(byte[]))
|
||||
{
|
||||
var si = new SecurityIdentifier((byte[])value, 0);
|
||||
|
||||
return si.Value;
|
||||
}
|
||||
else
|
||||
return result.Properties[propertyName]?[0]?.ToString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private async Task PopulateViewBagData()
|
||||
{
|
||||
var data = await _context.InfoBasesLists
|
||||
.OrderBy(c => c.Name)
|
||||
.ToListAsync();
|
||||
|
||||
ViewBag.AllInfoBasesLists = new SelectList(data, "Id", "Name");
|
||||
}
|
||||
|
||||
public async Task<IActionResult> GetUsers(int pageIndex = 1, string term = "")
|
||||
{
|
||||
const int pageSize = 50;
|
||||
|
||||
var source = _context.Users;
|
||||
|
||||
var count = 0;
|
||||
|
||||
if (string.IsNullOrEmpty(term))
|
||||
count = await source.CountAsync();
|
||||
else
|
||||
count = await source.Where(c => c.Name.Contains(term)).CountAsync();
|
||||
|
||||
var pagesAmount = (int)Math.Ceiling((double)count / pageSize);
|
||||
|
||||
var viewModel = new UserIndexViewModel
|
||||
{
|
||||
CurrentPage = pageIndex,
|
||||
PagesAmount = pagesAmount
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(term))
|
||||
{
|
||||
viewModel.Items = await source
|
||||
.OrderBy(c => c.Name)
|
||||
.Skip((pageSize * (pageIndex - 1)))
|
||||
.Take(pageSize)
|
||||
.ProjectTo<UserViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
viewModel.Items = await source
|
||||
.Where(c => c.Name.Contains(term))
|
||||
.OrderBy(c => c.Name)
|
||||
.Skip((pageSize * (pageIndex - 1)))
|
||||
.Take(pageSize)
|
||||
.ProjectTo<UserViewModel>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
return Json(viewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AdminPanel.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
[Authorize]
|
||||
public class WebCommonInfoBasesController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public WebCommonInfoBasesController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpHead]
|
||||
public IActionResult Cap()
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("CheckInfoBases")]
|
||||
public async Task<IActionResult> CheckInfoBases(string ClientId, string InfoBasesCheckCode)
|
||||
{
|
||||
if (!Guid.TryParse(ClientId, out Guid clientIdGuid) ||
|
||||
!Guid.TryParse(InfoBasesCheckCode, out Guid infoBasesCheckCodeGuid))
|
||||
return BadRequest();
|
||||
|
||||
var infoBasesChanged = false;
|
||||
var url = "";
|
||||
|
||||
if (clientIdGuid == Guid.Empty)
|
||||
infoBasesChanged = true;
|
||||
else
|
||||
{
|
||||
var user = await _context.Users
|
||||
.Include(c => c.InfoBasesList)
|
||||
.FirstOrDefaultAsync(c => c.Id == clientIdGuid);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
if (infoBasesCheckCodeGuid != user.InfoBasesList?.ListId)
|
||||
infoBasesChanged = true;
|
||||
}
|
||||
else
|
||||
infoBasesChanged = true;
|
||||
}
|
||||
|
||||
return Json(new { root = new { infoBasesChanged, url } });
|
||||
}
|
||||
|
||||
[HttpGet("GetInfoBases")]
|
||||
public async Task<IActionResult> GetInfoBases(string ClientId, string InfoBasesCheckCode)
|
||||
{
|
||||
if (!Guid.TryParse(ClientId, out Guid clientIdGuid) ||
|
||||
!Guid.TryParse(InfoBasesCheckCode, out Guid infoBasesCheckCodeGuid))
|
||||
return BadRequest();
|
||||
|
||||
string infoBases = "";
|
||||
|
||||
// Это первое обращение к сервису
|
||||
if (clientIdGuid == Guid.Empty)
|
||||
{
|
||||
if (HttpContext.User.Identity is WindowsIdentity windowsIdentity && windowsIdentity.IsAuthenticated)
|
||||
{
|
||||
var sid = windowsIdentity.User.Value;
|
||||
|
||||
// Ищем пользователя по sid
|
||||
var user = await GetUserBySid(sid);
|
||||
|
||||
GetInfoBases(user, ref clientIdGuid, ref infoBasesCheckCodeGuid, ref infoBases);
|
||||
}
|
||||
else // Пользователь не аутентифицирован, отправим путой список
|
||||
{
|
||||
infoBasesCheckCodeGuid = Guid.NewGuid();
|
||||
|
||||
infoBases = "";
|
||||
}
|
||||
}
|
||||
else // Это не первое обращение к сервису
|
||||
{
|
||||
var user = await GetUserById(clientIdGuid);
|
||||
|
||||
// Может быть так, что пользователь был пересоздан в базе данных сервиса, попробуем его найти по SID
|
||||
if (HttpContext.User.Identity is WindowsIdentity windowsIdentity && windowsIdentity.IsAuthenticated)
|
||||
{
|
||||
var sid = windowsIdentity.User.Value;
|
||||
|
||||
// Ищем пользователя по sid
|
||||
user = await GetUserBySid(sid);
|
||||
}
|
||||
|
||||
GetInfoBases(user, ref clientIdGuid, ref infoBasesCheckCodeGuid, ref infoBases);
|
||||
}
|
||||
|
||||
return Json(new { root = new { ClientId = clientIdGuid, InfoBasesCheckCode = infoBasesCheckCodeGuid, InfoBases = infoBases } });
|
||||
}
|
||||
|
||||
private async Task<User> GetUserById(Guid id)
|
||||
{
|
||||
return await _context.Users
|
||||
.Include(c => c.InfoBasesList)
|
||||
.ThenInclude(c => c.InfoBaseInfoBasesLists)
|
||||
.ThenInclude(c => c.InfoBase)
|
||||
.FirstOrDefaultAsync(c => c.Id == id);
|
||||
}
|
||||
private async Task<User> GetUserBySid(string sid)
|
||||
{
|
||||
return await _context.Users
|
||||
.Include(c => c.InfoBasesList)
|
||||
.ThenInclude(c => c.InfoBaseInfoBasesLists)
|
||||
.ThenInclude(c => c.InfoBase)
|
||||
.FirstOrDefaultAsync(c => c.Sid == sid);
|
||||
}
|
||||
private void GetInfoBases(User user, ref Guid clientIdGuid, ref Guid infoBasesCheckCodeGuid, ref string infoBases)
|
||||
{
|
||||
// Пользователь найден
|
||||
if (user != null)
|
||||
{
|
||||
clientIdGuid = user.Id;
|
||||
|
||||
// У пользователя установлен список информационных баз
|
||||
if (user.InfoBasesList != null)
|
||||
{
|
||||
// Проверка в первый раз, либо изменилось содержимое списка баз
|
||||
if (user.InfoBasesList.ListId != infoBasesCheckCodeGuid)
|
||||
infoBasesCheckCodeGuid = user.InfoBasesList.ListId;
|
||||
|
||||
infoBases = user.InfoBasesList.GetIBasesContent();
|
||||
}
|
||||
else // Список баз мог быть очищен
|
||||
{
|
||||
infoBasesCheckCodeGuid = Guid.NewGuid();
|
||||
|
||||
infoBases = "";
|
||||
}
|
||||
}
|
||||
else // пользователь не найден, отправим ему пустой список баз
|
||||
{
|
||||
infoBasesCheckCodeGuid = Guid.NewGuid();
|
||||
|
||||
infoBases = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace AdminPanel.Controllers
|
||||
{
|
||||
[Route("[controller]")]
|
||||
[ApiController]
|
||||
[AllowAnonymous]
|
||||
public class WebDistributiveLocationController : Controller
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public WebDistributiveLocationController(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
[HttpGet("GetDistributiveInfo")]
|
||||
public IActionResult GetDistributiveInfo(string OS, string Arch, string Version)
|
||||
{
|
||||
long size = 0;
|
||||
string url = "";
|
||||
|
||||
return Json(new { root = new { size, url } });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public class ErrorViewModel
|
||||
{
|
||||
public int StatusCode { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Details { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public class InfoBase
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public InfoBaseConnectionType ConnectionType { get; set; }
|
||||
public string Server { get; set; }
|
||||
public string InfoBaseName { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string URL { get; set; }
|
||||
public string IBasesContent { get; set; }
|
||||
public virtual List<InfoBaseInfoBasesList> InfoBaseInfoBasesLists { get; set; } = new List<InfoBaseInfoBasesList>();
|
||||
|
||||
public void SetIBasesContent()
|
||||
{
|
||||
if (ConnectionType == InfoBaseConnectionType.File)
|
||||
{
|
||||
IBasesContent =
|
||||
$"[{Name}]\n" +
|
||||
$"Connect=File=\"{Path}\";\n" +
|
||||
$"ID={Id}";
|
||||
}
|
||||
else if (ConnectionType == InfoBaseConnectionType.Server)
|
||||
{
|
||||
IBasesContent =
|
||||
$"[{Name}]\n" +
|
||||
$"Connect=Srvr=\"{Server}\";Ref=\"{InfoBaseName}\";\n" +
|
||||
$"ID={Id}";
|
||||
}
|
||||
else if (ConnectionType == InfoBaseConnectionType.WebServer)
|
||||
{
|
||||
IBasesContent =
|
||||
$"[{Name}]\n" +
|
||||
$"Connect=ws=\"{URL}\";\n" +
|
||||
$"ID={Id}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public enum InfoBaseConnectionType
|
||||
{
|
||||
[Display(Name = "Файловый")]
|
||||
File,
|
||||
[Display(Name = "На сервере 1С")]
|
||||
Server,
|
||||
[Display(Name = "На web сервере")]
|
||||
WebServer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using AutoMapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public class InfoBaseInfoBasesList
|
||||
{
|
||||
public Guid InfoBaseId { get; set; }
|
||||
public virtual InfoBase InfoBase { get; set; }
|
||||
public Guid InfoBasesListId { get; set; }
|
||||
public virtual InfoBasesList InfoBasesList { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public class InfoBasesList
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid ListId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public virtual List<InfoBaseInfoBasesList> InfoBaseInfoBasesLists { get; set; } = new List<InfoBaseInfoBasesList>();
|
||||
public virtual List<User> Users { get; set; } = new List<User>();
|
||||
|
||||
public string GetIBasesContent()
|
||||
{
|
||||
var data = "";
|
||||
|
||||
foreach (var item in InfoBaseInfoBasesLists)
|
||||
{
|
||||
data += item.InfoBase.IBasesContent + "\n";
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.Models
|
||||
{
|
||||
public class User
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string Sid { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string SamAccountName { get; set; }
|
||||
public Guid? InfoBasesListId { get; set; }
|
||||
public virtual InfoBasesList InfoBasesList { get; set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is User user &&
|
||||
Sid == user.Sid &&
|
||||
Name == user.Name &&
|
||||
SamAccountName == user.SamAccountName;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Sid, Name, SamAccountName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using AutoMapper;
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using Microsoft.CodeAnalysis.FlowAnalysis;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
|
||||
namespace AdminPanel.Profiles
|
||||
{
|
||||
public class InfoBaseInfoBasesListProfile : Profile
|
||||
{
|
||||
public InfoBaseInfoBasesListProfile()
|
||||
{
|
||||
CreateMap<InfoBaseInfoBasesList, InfoBaseInfoBasesListViewModel>();
|
||||
|
||||
CreateMap<InfoBaseInfoBasesListViewModel, InfoBaseInfoBasesList>()
|
||||
.ForMember(dest => dest.InfoBase, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.InfoBasesList, opt => opt.Ignore());
|
||||
|
||||
CreateMap<InfoBaseInfoBasesList, InfoBaseItemViewModel>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.InfoBaseId))
|
||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.InfoBase.Name));
|
||||
|
||||
CreateMap<InfoBaseItemViewModel, InfoBaseInfoBasesList>()
|
||||
.ForMember(dest => dest.InfoBaseId, opt => opt.MapFrom(src => src.Id));
|
||||
|
||||
CreateMap<InfoBaseInfoBasesList, InfoBasesListItemViewModel>()
|
||||
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.InfoBasesListId))
|
||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.InfoBasesList.Name));
|
||||
|
||||
CreateMap<InfoBasesListItemViewModel, InfoBaseInfoBasesList>()
|
||||
.ForMember(dest => dest.InfoBasesListId, opt => opt.MapFrom(src => src.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using AutoMapper;
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
|
||||
namespace AdminPanel.Profiles
|
||||
{
|
||||
public class InfoBaseProfile : Profile
|
||||
{
|
||||
public InfoBaseProfile()
|
||||
{
|
||||
CreateMap<InfoBase, InfoBase>()
|
||||
.ForMember(dest => dest.InfoBaseInfoBasesLists, opt => opt.Ignore());
|
||||
|
||||
CreateMap<InfoBase, InfoBaseViewModel>()
|
||||
.ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using AutoMapper;
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using AdminPanel.ViewModels.Users;
|
||||
using System.Linq;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
|
||||
namespace AdminPanel.Profiles
|
||||
{
|
||||
public class InfoBasesListProfile : Profile
|
||||
{
|
||||
public InfoBasesListProfile()
|
||||
{
|
||||
CreateMap<InfoBasesList, InfoBasesList>()
|
||||
.ForMember(dest => dest.InfoBaseInfoBasesLists, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Users, opt => opt.Ignore());
|
||||
|
||||
CreateMap<InfoBasesList, InfoBasesListViewModel>().ReverseMap();
|
||||
|
||||
CreateMap<InfoBasesList, InfoBasesListItemViewModel>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using AutoMapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.Users;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
|
||||
namespace AdminPanel.Profiles
|
||||
{
|
||||
public class UserProfile : Profile
|
||||
{
|
||||
public UserProfile()
|
||||
{
|
||||
CreateMap<User, UserViewModel>();
|
||||
|
||||
CreateMap<UserViewModel, User>()
|
||||
.ForMember(dest => dest.InfoBasesList, opt => opt.Ignore());
|
||||
|
||||
CreateMap<User, ItemViewModel>();
|
||||
|
||||
CreateMap<ItemViewModel, User>()
|
||||
.ForMember(dest => dest.Name, opt => opt.Ignore());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Hosting.WindowsServices;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Threading;
|
||||
|
||||
namespace AdminPanel
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.UseWindowsService()
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": true,
|
||||
"anonymousAuthentication": false,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:61056",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"AdminPanel": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
namespace Common {
|
||||
export class ItemViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
function setAddButtonAvailability(select: HTMLElement, addButton: HTMLElement): void {
|
||||
if ($(select).children().length > 0) {
|
||||
$(addButton).removeClass('disabled')
|
||||
.prop('disabled', false);
|
||||
}
|
||||
else {
|
||||
$(addButton).addClass('disabled')
|
||||
.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
|
||||
function removeOption(select: HTMLElement, addButton: HTMLElement, value: string | number | string[]) {
|
||||
$(select).children('option').each(function (index, elem) {
|
||||
if ($(elem).val() == value) {
|
||||
$(elem).remove();
|
||||
}
|
||||
});
|
||||
|
||||
setAddButtonAvailability(select, addButton);
|
||||
}
|
||||
|
||||
function addOption(select: HTMLElement, addButton: HTMLElement, text: string, value: string) {
|
||||
const option = document.createElement('option');
|
||||
$(option).val(value)
|
||||
.text(text)
|
||||
.appendTo(select);
|
||||
|
||||
setAddButtonAvailability(select, addButton);
|
||||
}
|
||||
|
||||
function removeRow(select: HTMLElement, table: HTMLElement, addButton: HTMLElement, deleteButton: HTMLElement): void {
|
||||
let text;
|
||||
var value;
|
||||
|
||||
const tr = $(deleteButton).closest('tr');
|
||||
|
||||
const idInput = $(tr).find(':input:hidden').first();
|
||||
value = idInput.val();
|
||||
text = idInput.closest('td').text();
|
||||
|
||||
tr.remove();
|
||||
|
||||
addOption(select, addButton, text, value);
|
||||
}
|
||||
|
||||
function addRow(select: HTMLSelectElement, table: HTMLElement, addButton: HTMLElement): void {
|
||||
const selectedIndex = $(select).prop('selectedIndex');
|
||||
const selectedItem = $(select).children().eq(selectedIndex);
|
||||
const value = $(selectedItem).val();
|
||||
const label = $(selectedItem).text();
|
||||
|
||||
const tbody = $(table).find('tbody');
|
||||
|
||||
const tableId = $(table).attr('id');
|
||||
|
||||
const row = document.createElement('tr');
|
||||
$(row).appendTo(tbody);
|
||||
|
||||
const col1 = document.createElement('td');
|
||||
$(col1).text(label)
|
||||
.appendTo(row);
|
||||
|
||||
const inputName = document.createElement('input');
|
||||
$(inputName).val(value)
|
||||
.attr('type', 'hidden')
|
||||
.attr('name', `${tableId}`)
|
||||
.appendTo(col1);
|
||||
|
||||
const col2 = document.createElement('td');
|
||||
$(col2).appendTo(row);
|
||||
|
||||
const deleteBtn = document.createElement('button');
|
||||
$(deleteBtn).attr('type', 'button')
|
||||
.addClass('btn btn-danger')
|
||||
.click(function (event) {
|
||||
removeRow(select, table, addButton, event.currentTarget);
|
||||
})
|
||||
.appendTo(col2);
|
||||
|
||||
const deleteI = document.createElement('i');
|
||||
$(deleteI).addClass('fa fa-trash')
|
||||
.appendTo(deleteBtn);
|
||||
|
||||
removeOption(select, addButton, value);
|
||||
}
|
||||
|
||||
export function connectSelectToTable(select: HTMLSelectElement, addButton: HTMLElement, table: HTMLTableElement) {
|
||||
|
||||
setAddButtonAvailability(select, addButton);
|
||||
|
||||
$(addButton).click(function () {
|
||||
addRow(select, table, addButton);
|
||||
});
|
||||
|
||||
$(table).find('.fa-trash').each(function (index, elem) {
|
||||
$(elem).closest('button').click(() =>
|
||||
removeRow(select, table, addButton, elem));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfoBases {
|
||||
export class InfoBaseItemViewModel extends Common.ItemViewModel {}
|
||||
|
||||
export class InfoBaseViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
server: string;
|
||||
infoBaseName: string;
|
||||
iBasesContent: string;
|
||||
infoBasesLists: InfoBasesLists.InfoBasesListItemViewModel[];
|
||||
}
|
||||
|
||||
export class InfoBaseIndexViewModel {
|
||||
currentPage: number;
|
||||
pagesAmount: number;
|
||||
items: InfoBaseViewModel[];
|
||||
}
|
||||
|
||||
function showFormGroupFor(elem): void {
|
||||
$(elem).closest('.form-group')
|
||||
.show();
|
||||
}
|
||||
|
||||
function hideFormGroupFor(elem): void {
|
||||
$(elem).val('')
|
||||
.closest('.form-group')
|
||||
.hide();
|
||||
}
|
||||
|
||||
function setGroupsVisibility() {
|
||||
const select = $('#ConnectionType');
|
||||
const selectedIndex = $(select).prop('selectedIndex');
|
||||
const value = $(select).children().eq(selectedIndex).val();
|
||||
|
||||
switch (value) {
|
||||
case "0":
|
||||
showFormGroupFor($('#Path'));
|
||||
hideFormGroupFor($('#URL'));
|
||||
hideFormGroupFor($('#Server'));
|
||||
hideFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
case "1":
|
||||
hideFormGroupFor($('#Path'));
|
||||
hideFormGroupFor($('#URL'));
|
||||
showFormGroupFor($('#Server'));
|
||||
showFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
case "2":
|
||||
hideFormGroupFor($('#Path'));
|
||||
showFormGroupFor($('#URL'));
|
||||
hideFormGroupFor($('#Server'));
|
||||
hideFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export function initInfoBaseCreateEditView(): void {
|
||||
|
||||
setGroupsVisibility();
|
||||
|
||||
$('#ConnectionType').change(function(e, t) {
|
||||
setGroupsVisibility();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
namespace InfoBasesLists {
|
||||
export class InfoBasesListItemViewModel extends Common.ItemViewModel {}
|
||||
|
||||
export class InfoBasesListViewModel{
|
||||
id: string;
|
||||
name: string;
|
||||
listId: string;
|
||||
infoBases: InfoBases.InfoBaseItemViewModel[];
|
||||
users: Common.ItemViewModel[];
|
||||
}
|
||||
|
||||
export class InfoBasesListIndexViewModel {
|
||||
currentPage: number;
|
||||
pagesAmount: number;
|
||||
items: InfoBasesListViewModel[];
|
||||
}
|
||||
}
|
||||
|
||||
namespace Users {
|
||||
export class UserViewModel {
|
||||
id: string;
|
||||
name: string;
|
||||
sid: string;
|
||||
samAccountName: string;
|
||||
infoBasesListId: string;
|
||||
infoBasesList: Common.ItemViewModel;
|
||||
}
|
||||
|
||||
export class UserIndexViewModel {
|
||||
currentPage: number;
|
||||
pagesAmount: number;
|
||||
items: UserViewModel[];
|
||||
}
|
||||
|
||||
export async function updateFromActiveDirectory(): Promise<void> {
|
||||
const btn = $('#updateFromAd');
|
||||
|
||||
btn.addClass('disabled')
|
||||
.prop('disabled', true);
|
||||
|
||||
const response = await fetch('/Users/UpdateFromActiveDirectory');
|
||||
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Не удалось обновить список пользователей');
|
||||
}
|
||||
|
||||
btn.removeClass('disabled')
|
||||
.prop('disabled', false);
|
||||
}
|
||||
|
||||
export async function initIndexView(): Promise<void> {
|
||||
const url = '/Users/GetUsers';
|
||||
|
||||
await getUsers(url, 1, '');
|
||||
|
||||
var time = 0;
|
||||
|
||||
$('#searchBox').keyup(async function (event) {
|
||||
clearTimeout(time);
|
||||
|
||||
time = window.setTimeout(async function () {
|
||||
const term = $('#searchBox').val();
|
||||
await getUsers(url, 1, term);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
|
||||
async function getUsers(url: string, pageIndex: number, term: string | number | string[]): Promise<void> {
|
||||
let urlParams = `${url}?pageIndex=${pageIndex}`
|
||||
|
||||
if (term != '')
|
||||
urlParams += `&term=${term}`;
|
||||
|
||||
const response = await fetch(urlParams);
|
||||
|
||||
if (response.ok) {
|
||||
const data: Users.UserIndexViewModel = await response.json();
|
||||
|
||||
fillUsersTable(data);
|
||||
|
||||
fillUsersPagesNav(data, url, term);
|
||||
} else {
|
||||
alert('Не удалось получить список пользователей');
|
||||
}
|
||||
}
|
||||
|
||||
function fillUsersTable(userIndexViewModel: Users.UserIndexViewModel): void {
|
||||
const tbody = $('#dataTable').children('tbody').first().empty();
|
||||
|
||||
userIndexViewModel.items.forEach(function (value) {
|
||||
const tr = document.createElement('tr');
|
||||
$(tr).appendTo(tbody);
|
||||
|
||||
const tdName = document.createElement('td');
|
||||
$(tdName).text(value.name)
|
||||
.appendTo(tr);
|
||||
|
||||
const tdSamAccountName = document.createElement('td');
|
||||
$(tdSamAccountName).text(value.samAccountName)
|
||||
.appendTo(tr);
|
||||
|
||||
const tdInfoBasesListName = document.createElement('td');
|
||||
$(tdInfoBasesListName).appendTo(tr);
|
||||
|
||||
if (value.infoBasesList != null)
|
||||
$(tdInfoBasesListName).text(value.infoBasesList.name)
|
||||
|
||||
const tdActions = document.createElement('td');
|
||||
$(tdActions).appendTo(tr);
|
||||
|
||||
const aEdit = document.createElement('a');
|
||||
$(aEdit).addClass('btn btn-secondary col-auto m-1')
|
||||
.attr('href', `/Users/Edit/${value.id}`)
|
||||
.appendTo(tdActions);
|
||||
|
||||
const iEdit = document.createElement('i');
|
||||
$(iEdit).addClass('fa fa-edit')
|
||||
.appendTo(aEdit);
|
||||
|
||||
const aDelete = document.createElement('a');
|
||||
$(aDelete).addClass('btn btn-danger col-auto m-1')
|
||||
.attr('href', `/Users/Delete/${value.id}`)
|
||||
.appendTo(tdActions);
|
||||
|
||||
const iDelete = document.createElement('i');
|
||||
$(iDelete).addClass('fa fa-trash')
|
||||
.appendTo(aDelete);
|
||||
});
|
||||
}
|
||||
|
||||
function fillUsersPagesNav(userIndexViewModel: Users.UserIndexViewModel, url: string, term: string | number | string[]): void {
|
||||
const ul = $('#pagesNav').children('ul').first().empty();
|
||||
|
||||
if (userIndexViewModel.pagesAmount > 1) {
|
||||
for (let i = 1; i <= userIndexViewModel.pagesAmount; i++) {
|
||||
const li = document.createElement('li');
|
||||
$(li).addClass('page-item')
|
||||
.appendTo(ul);
|
||||
|
||||
if (i === userIndexViewModel.currentPage)
|
||||
$(li).addClass('active');
|
||||
|
||||
const a = document.createElement('a');
|
||||
$(a).text(i)
|
||||
.attr('href', '#')
|
||||
.addClass('page-link')
|
||||
.click(async function () {
|
||||
await getUsers(url, i, term);
|
||||
})
|
||||
.appendTo(li);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": false,
|
||||
"noEmitOnError": true,
|
||||
"removeComments": false,
|
||||
"sourceMap": true,
|
||||
"target": "es5",
|
||||
"outDir": "../wwwroot/js"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"wwwroot"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AutoMapper;
|
||||
using AutoMapper.EquivalencyExpression;
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace AdminPanel
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
|
||||
.AddNegotiate();
|
||||
|
||||
var adminGroup = Configuration["Security:AdminGroup"];
|
||||
|
||||
services.AddAuthorization(opt =>
|
||||
opt.AddPolicy("OnlyAdmins", policy =>
|
||||
{
|
||||
policy.RequireAuthenticatedUser();
|
||||
policy.RequireRole(adminGroup);
|
||||
}));
|
||||
|
||||
services.AddAutoMapper(c => c.AddCollectionMappers(), typeof(Startup));
|
||||
services.AddControllersWithViews();
|
||||
services.AddEntityFrameworkSqlServer()
|
||||
.AddDbContext<AppDbContext>((sp, opt) =>
|
||||
opt.UseSqlServer(Configuration["ConnectionStrings:Default"])
|
||||
.UseInternalServiceProvider(sp));
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
//env.EnvironmentName = "Production";
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Users}/{action=Index}/{id?}");
|
||||
//.RequireAuthorization();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.Common
|
||||
{
|
||||
public class IndexViewModel<T>
|
||||
{
|
||||
public int CurrentPage { get; set; } = 1;
|
||||
public int PagesAmount { get; set; }
|
||||
public List<T> Items { get; set; } = new List<T>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.Common
|
||||
{
|
||||
public class ItemViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
public Guid Id { get; set; }
|
||||
[Display(Name = "Наименование")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels
|
||||
{
|
||||
public class InfoBaseInfoBasesListViewModel
|
||||
{
|
||||
public Guid InfoBaseId { get; set; }
|
||||
public InfoBaseViewModel InfoBase { get; set; }
|
||||
public Guid InfoBasesListId { get; set; }
|
||||
public InfoBasesListViewModel InfoBasesList { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AdminPanel.ViewModels.InfoBases
|
||||
{
|
||||
[Display(Name = "Информационные базы")]
|
||||
public class InfoBaseIndexViewModel
|
||||
{
|
||||
[Display(Name = "Текущая страница")]
|
||||
public int CurrentPage { get; set; } = 1;
|
||||
[Display(Name = "Количество")]
|
||||
public int PagesAmount { get; set; }
|
||||
[Display(Name = "Информационные базы")]
|
||||
public List<InfoBaseViewModel> Items { get; set; } = new List<InfoBaseViewModel>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using AdminPanel.ViewModels.Common;
|
||||
|
||||
namespace AdminPanel.ViewModels.InfoBases
|
||||
{
|
||||
public class InfoBaseItemViewModel : ItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.InfoBases
|
||||
{
|
||||
[Display(Name = "Информационная база")]
|
||||
public class InfoBaseViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
public Guid Id { get; set; }
|
||||
[Display(Name = "Наименование")]
|
||||
[Required(ErrorMessage = "Не заполнено наименование")]
|
||||
public string Name { get; set; }
|
||||
[Display(Name = "Вариант расположения")]
|
||||
[Required(ErrorMessage = "Не указан вариант расположения информационной базы")]
|
||||
public InfoBaseConnectionType ConnectionType { get; set; }
|
||||
[Display(Name = "Сервер")]
|
||||
[Required(ErrorMessage = "Не указан адрес сервера информационной базы")]
|
||||
public string Server { get; set; }
|
||||
[Display(Name = "Имя информационной базы")]
|
||||
[Required(ErrorMessage = "Не заполнено имя информационной базы")]
|
||||
public string InfoBaseName { get; set; }
|
||||
[Display(Name = "Каталог информационной базы")]
|
||||
[Required(ErrorMessage = "Не заполнен каталог информационной базы")]
|
||||
public string Path { get; set; }
|
||||
[Display(Name = "Адрес информационной базы")]
|
||||
[Required(ErrorMessage = "Не заполнен адрес информационной базы")]
|
||||
public string URL { get; set; }
|
||||
[HiddenInput]
|
||||
public string IBasesContent { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace AdminPanel.ViewModels.InfoBasesLists
|
||||
{
|
||||
[Display(Name = "Списки информационных баз")]
|
||||
public class InfoBasesListIndexViewModel
|
||||
{
|
||||
[Display(Name = "Текущая страница")]
|
||||
public int CurrentPage { get; set; } = 1;
|
||||
[Display(Name = "Количество")]
|
||||
public int PagesAmount { get; set; }
|
||||
[Display(Name = "Списки информационных баз")]
|
||||
public List<InfoBasesListViewModel> Items { get; set; } = new List<InfoBasesListViewModel>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AdminPanel.ViewModels.Common
|
||||
{
|
||||
public class InfoBasesListItemViewModel : ItemViewModel
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.Users;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.InfoBasesLists
|
||||
{
|
||||
[Display(Name = "Список информационных баз")]
|
||||
public class InfoBasesListViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
public Guid Id { get; set; }
|
||||
[HiddenInput]
|
||||
public Guid ListId { get; set; }
|
||||
[Display(Name = "Наименование")]
|
||||
[Required( ErrorMessage = "Не заполнено наименование")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using AdminPanel.Models;
|
||||
using AdminPanel.ViewModels.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.Users
|
||||
{
|
||||
[Display(Name = "Пользователи")]
|
||||
public class UserIndexViewModel
|
||||
{
|
||||
[Display(Name = "Текущая страница")]
|
||||
public int CurrentPage { get; set; } = 1;
|
||||
[Display(Name = "Количество")]
|
||||
public int PagesAmount{ get; set; }
|
||||
[Display(Name = "Пользователи")]
|
||||
public List<UserViewModel> Items { get; set; } = new List<UserViewModel>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using AdminPanel.ViewModels.Common;
|
||||
using AdminPanel.ViewModels.InfoBases;
|
||||
using AdminPanel.ViewModels.InfoBasesLists;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdminPanel.ViewModels.Users
|
||||
{
|
||||
[Display(Name = "Пользователь")]
|
||||
public class UserViewModel
|
||||
{
|
||||
[HiddenInput]
|
||||
public Guid Id { get; set; }
|
||||
[HiddenInput]
|
||||
public string Sid { get; set; }
|
||||
[Display(Name = "Имя")]
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
[Display(Name = "Имя AD")]
|
||||
[Required]
|
||||
public string SamAccountName { get; set; }
|
||||
[HiddenInput]
|
||||
public Guid? InfoBasesListId { get; set; }
|
||||
[Display(Name = "Список информационных баз")]
|
||||
public InfoBasesListItemViewModel InfoBasesList { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@model AdminPanel.ViewModels.InfoBases.InfoBaseViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Создание";
|
||||
}
|
||||
|
||||
<h1>Создание</h1>
|
||||
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<form asp-action="Create">
|
||||
<div class="form-group">
|
||||
<ul class="nav nav-command-panel">
|
||||
<li class="nav-item">
|
||||
<input type="submit" value="Записать" class="btn btn-primary" />
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-action="Index" class="btn btn-secondary">К списку</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@{ await Html.RenderPartialAsync("_CreateEdit", Model); }
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
@model AdminPanel.ViewModels.InfoBases.InfoBaseViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Удаление";
|
||||
}
|
||||
|
||||
<h1>Удаление</h1>
|
||||
|
||||
<h3>Информационная база будет удалена из списков всех пользователей, продолжить?</h3>
|
||||
<div>
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<dl class="row">
|
||||
<dt class = "col-sm-2">
|
||||
@Html.DisplayNameFor(model => model.Name)
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@Html.DisplayFor(model => model.Name)
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<form asp-action="Delete">
|
||||
<input type="submit" value="Удалить" class="btn btn-danger" /> |
|
||||
<a asp-action="Index">К списку</a>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
@model AdminPanel.ViewModels.InfoBases.InfoBaseViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Редактирование";
|
||||
}
|
||||
|
||||
<h1>Редактирование</h1>
|
||||
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<form asp-action="Edit">
|
||||
<div class="form-group">
|
||||
<ul class="nav nav-command-panel">
|
||||
<li class="nav-item">
|
||||
<input type="submit" value="Записать" class="btn btn-primary" />
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-action="Index" class="btn btn-secondary">К списку</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@{ await Html.RenderPartialAsync("_CreateEdit", Model); }
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
@model AdminPanel.ViewModels.InfoBases.InfoBaseIndexViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = Html.DisplayNameForModel();
|
||||
}
|
||||
|
||||
<h1>@Html.DisplayNameForModel()</h1>
|
||||
|
||||
<p>
|
||||
<a class="btn btn-primary" asp-action="Create">Создать</a>
|
||||
</p>
|
||||
<table class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>
|
||||
@Html.DisplayNameFor(itemModel => itemModel.Items[0].Name)
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model.Items)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Name)
|
||||
</td>
|
||||
<td>
|
||||
<a asp-action="Edit" class="btn btn-secondary" asp-route-id="@item.Id">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
<a asp-action="Delete" class="btn btn-danger" asp-route-id="@item.Id">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (Model.PagesAmount > 1)
|
||||
{
|
||||
<nav aria-label="Page navigation" >
|
||||
<ul class="pagination justify-content-center">
|
||||
@for (int i = 1; i <= Model.PagesAmount; i++)
|
||||
{
|
||||
var addClass = Model.CurrentPage == i ? "active" : "";
|
||||
|
||||
<li class="page-item @addClass">
|
||||
<a class="page-link" href="/InfoBases?page=@i">@i</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
@model AdminPanel.ViewModels.InfoBases.InfoBaseViewModel
|
||||
|
||||
@{
|
||||
var selectedInfoBasesLists = ViewBag.SelectedInfoBasesLists as List<(Guid Id, string Name)>;
|
||||
var allInfoBasesLists = ViewBag.AllInfoBasesLists as SelectList;
|
||||
}
|
||||
|
||||
<div class="col-md-4 no-padding">
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="ConnectionType" class="control-label"></label>
|
||||
@Html.DropDownListFor(c => c.ConnectionType, Html.GetEnumSelectList<InfoBaseConnectionType>(), null, new { @class = "custom-select" })
|
||||
<span asp-validation-for="ConnectionType" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Server" class="control-label"></label>
|
||||
<input asp-for="Server" class="form-control" />
|
||||
<span asp-validation-for="Server" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="InfoBaseName" class="control-label"></label>
|
||||
<input asp-for="InfoBaseName" class="form-control" />
|
||||
<span asp-validation-for="InfoBaseName" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Path" class="control-label"></label>
|
||||
<input asp-for="Path" class="form-control" />
|
||||
<span asp-validation-for="Path" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="URL" class="control-label"></label>
|
||||
<input asp-for="URL" class="form-control" />
|
||||
<span asp-validation-for="URL" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-10 no-padding">
|
||||
<div class="form-group">
|
||||
<label class="control-label">Список информационных баз</label>
|
||||
<div class="form-row">
|
||||
<div class="col">
|
||||
<select id="selectInfoBasesList" class="custom-select">
|
||||
@foreach (var item in allInfoBasesLists)
|
||||
{
|
||||
<option value="@item.Value">@item.Text</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button id="addInfoBaseList" type="button" class="btn btn-primary">Добавить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<table id="selectedInfoBasesLists" class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Наименование</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in selectedInfoBasesLists)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@item.Name
|
||||
<input type="hidden" name="selectedInfoBasesLists" value="@item.Id" />
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
Common.connectSelectToTable($('#selectInfoBasesList'), $('#addInfoBaseList'), $('#selectedInfoBasesLists'));
|
||||
|
||||
InfoBases.initInfoBaseCreateEditView();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,27 @@
|
||||
@model AdminPanel.ViewModels.InfoBasesLists.InfoBasesListViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Создание";
|
||||
}
|
||||
|
||||
<h1>Создание</h1>
|
||||
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<form asp-action="Create">
|
||||
<div class="form-group">
|
||||
<ul class="nav nav-command-panel">
|
||||
<li class="nav-item">
|
||||
<input type="submit" value="Записать" class="btn btn-primary" />
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-action="Index" class="btn btn-secondary">К списку</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@{ await Html.RenderPartialAsync("_CreateEdit", Model); }
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@model AdminPanel.ViewModels.InfoBasesLists.InfoBasesListViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Удаление";
|
||||
}
|
||||
|
||||
<h1>Удаление</h1>
|
||||
|
||||
<h3>Список информационных баз будет очищен у пользователей, которые его используют и удален. Продолжить?</h3>
|
||||
<div>
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">
|
||||
@Html.DisplayNameFor(model => model.Name)
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
@Html.DisplayFor(model => model.Name)
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<form asp-action="Delete">
|
||||
<input type="submit" value="Удалить" class="btn btn-danger" /> |
|
||||
<a asp-action="Index">К списку</a>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,27 @@
|
||||
@model AdminPanel.ViewModels.InfoBasesLists.InfoBasesListViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Редактирование";
|
||||
}
|
||||
|
||||
<h1>Редактирование</h1>
|
||||
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<form asp-action="Edit">
|
||||
<div class="form-group">
|
||||
<ul class="nav nav-command-panel">
|
||||
<li class="nav-item">
|
||||
<input type="submit" value="Записать" class="btn btn-primary" />
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-action="Index" class="btn btn-secondary">К списку</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@{ await Html.RenderPartialAsync("_CreateEdit", Model); }
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
@model AdminPanel.ViewModels.InfoBasesLists.InfoBasesListIndexViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = Html.DisplayNameForModel();
|
||||
}
|
||||
|
||||
<h1>@Html.DisplayNameForModel()</h1>
|
||||
|
||||
<p>
|
||||
<a class="btn btn-primary" asp-action="Create">Создать</a>
|
||||
</p>
|
||||
<table class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>
|
||||
@Html.DisplayNameFor(itemModel => itemModel.Items[0].Name)
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in Model.Items)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@Html.DisplayFor(modelItem => item.Name)
|
||||
</td>
|
||||
<td>
|
||||
<a asp-action="Edit" class="btn btn-secondary" asp-route-id="@item.Id">
|
||||
<i class="fa fa-edit"></i>
|
||||
</a>
|
||||
<a asp-action="Delete" class="btn btn-danger" asp-route-id="@item.Id">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
@if (Model.PagesAmount > 1)
|
||||
{
|
||||
<nav aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center">
|
||||
@for (int i = 1; i <= Model.PagesAmount; i++)
|
||||
{
|
||||
var addClass = Model.CurrentPage == i ? "active" : "";
|
||||
|
||||
<li class="page-item @addClass">
|
||||
<a class="page-link" href="/InfoBasesLists?page=@i">@i</a>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
@model AdminPanel.ViewModels.InfoBasesLists.InfoBasesListViewModel
|
||||
|
||||
@{
|
||||
var selectedInfoBases = ViewBag.SelectedInfoBases as List<(Guid Id, string Name)>;
|
||||
var allInfoBases = ViewBag.AllInfoBases as SelectList;
|
||||
var selectedUsers = ViewBag.SelectedUsers as List<(Guid Id, string Name)>;
|
||||
var allUsers = ViewBag.AllUsers as SelectList;
|
||||
}
|
||||
|
||||
<div class="col-md-4 no-padding">
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
<ul id="myTab" role="tablist" class="nav nav-tabs">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="ibs-tab" data-toggle="tab" role="tab" aria-controls="ibs" aria-selected="true" href="#ibs">Информационные базы</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="us-tab" data-toggle="tab" role="tab" aria-controls="us" aria-selected="false" href="#us">Пользователи</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="myTabContent" style="padding-top: 10px" class="tab-content">
|
||||
<div class="tab-pane fade show active" role="tabpanel" aria-labelledby="ibs-tab" id="ibs">
|
||||
<div class="form-group">
|
||||
<div class="form-row">
|
||||
<div class="col">
|
||||
<select id="selectInfoBases" class="custom-select">
|
||||
@foreach (var item in allInfoBases)
|
||||
{
|
||||
<option value="@item.Value">@item.Text</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button id="addInfoBase" type="button" class="btn btn-primary">Добавить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<table id="selectedInfoBases" class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Наименование</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in selectedInfoBases)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@item.Name
|
||||
<input type="hidden" name="selectedInfoBases" value="@item.Id" />
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" role="tabpanel" aria-labelledby="us-tab" id="us">
|
||||
<div class="form-group">
|
||||
<div class="form-row">
|
||||
<div class="col">
|
||||
<select id="selectUsers" class="custom-select">
|
||||
@foreach (var item in allUsers)
|
||||
{
|
||||
<option value="@item.Value">@item.Text</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button id="addUser" type="button" class="btn btn-primary">Добавить</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<table id="selectedUsers" class="table table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Наименование</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var item in selectedUsers)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@item.Name
|
||||
<input type="hidden" name="selectedUsers" value="@item.Id" />
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-danger">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
Common.connectSelectToTable($('#selectInfoBases'), $('#addInfoBase'), $('#selectedInfoBases'));
|
||||
Common.connectSelectToTable($('#selectUsers'), $('#addUser'), $('#selectedUsers'));
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,8 @@
|
||||
@model ErrorViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Error";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">@Model.Title</h1>
|
||||
<h2 class="text-danger">@Model.Details</h2>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>@ViewData["Title"] - AdminPanel</title>
|
||||
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="~/lib/fontawesome-free/css/all.min.css" />
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||
@RenderSection("Scripts", required: false)
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" asp-area="" asp-controller="Users" asp-action="Index">AdminPanel</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
|
||||
<ul class="navbar-nav flex-grow-1">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="Users" asp-action="Index">Пользователи</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="InfoBasesLists" asp-action="Index">Списки</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-light" asp-area="" asp-controller="InfoBases" asp-action="Index">Информационные базы</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container" style="margin-bottom: 60px">
|
||||
<main role="main" class="pb-3">
|
||||
@RenderBody()
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,2 @@
|
||||
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
|
||||
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
|
||||
@@ -0,0 +1,31 @@
|
||||
@model AdminPanel.ViewModels.Users.UserViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Удаление";
|
||||
}
|
||||
|
||||
<h1>Удаление</h1>
|
||||
|
||||
<h3>Пользователь будет удален, продолжить?</h3>
|
||||
<div>
|
||||
<dl class="row">
|
||||
<dt class = "col-sm-2">
|
||||
@Html.DisplayNameFor(model => model.Name)
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@Html.DisplayFor(model => model.Name)
|
||||
</dd>
|
||||
<dt class = "col-sm-2">
|
||||
@Html.DisplayNameFor(model => model.SamAccountName)
|
||||
</dt>
|
||||
<dd class = "col-sm-10">
|
||||
@Html.DisplayFor(model => model.SamAccountName)
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<form asp-action="Delete">
|
||||
<input type="hidden" asp-for="Id" />
|
||||
<input type="submit" value="Удалить" class="btn btn-danger" /> |
|
||||
<a asp-action="Index">К списку</a>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
@model AdminPanel.ViewModels.Users.UserViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Редактирование";
|
||||
var allInfoBasesLists = ViewBag.AllInfoBasesLists as SelectList;
|
||||
}
|
||||
|
||||
<h1>Редактирование</h1>
|
||||
|
||||
<h4>@Html.DisplayNameForModel()</h4>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form asp-action="Edit">
|
||||
<div class="form-group">
|
||||
<ul class="nav nav-command-panel">
|
||||
<li class="nav-item">
|
||||
<input type="submit" value="Записать" class="btn btn-primary" />
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a asp-action="Index" class="btn btn-secondary">К списку</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
|
||||
<input asp-for="Id" type="hidden" class="form-control" />
|
||||
<input asp-for="Sid" type="hidden" class="form-control" />
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<input asp-for="Name" type="hidden" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="SamAccountName" class="control-label"></label>
|
||||
<input asp-for="SamAccountName" class="form-control" />
|
||||
<input asp-for="SamAccountName" type="hidden" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="InfoBasesList" class="control-label"></label>
|
||||
@Html.DropDownListFor(itemModel => itemModel.InfoBasesListId, allInfoBasesLists, "--Выберите значение--", new { @class = "custom-select" })
|
||||
<input asp-for="InfoBasesList" type="hidden" class="form-control" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
@model AdminPanel.ViewModels.Users.UserIndexViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = Html.DisplayNameForModel();
|
||||
}
|
||||
|
||||
<h1>@Html.DisplayNameForModel()</h1>
|
||||
|
||||
<div class="form-group">
|
||||
<ul class="nav row">
|
||||
<li class="nav-item col-sm-auto mr-sm-auto">
|
||||
<button onclick="Users.updateFromActiveDirectory()" id="updateFromAd" class="btn btn-primary col-sm-auto">Обновить из ActiveDirectory</button>
|
||||
</li>
|
||||
<li class="nav-item col-sm-auto float-sm-right mt-2 mt-sm-0">
|
||||
<input id="searchBox" type="text" class="form-control" placeholder="Поиск" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<table id="dataTable" class="table table-sm-sm table-responsive-sm table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>
|
||||
@Html.DisplayNameFor(itemModel => itemModel.Items[0].Name)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(itemModel => itemModel.Items[0].SamAccountName)
|
||||
</th>
|
||||
<th>
|
||||
@Html.DisplayNameFor(itemModel => itemModel.Items[0].InfoBasesList)
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
<nav id="pagesNav" aria-label="Page navigation">
|
||||
<ul class="pagination justify-content-center"></ul>
|
||||
</nav>
|
||||
|
||||
<script>
|
||||
$(async function () {
|
||||
await Users.initIndexView();
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,3 @@
|
||||
@using AdminPanel
|
||||
@using AdminPanel.Models
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@@ -0,0 +1,3 @@
|
||||
@{
|
||||
Layout = "_Layout";
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"Default": "Data Source=localhost;Initial Catalog=AdminPanel;Integrated Security=True;"
|
||||
},
|
||||
"Security": {
|
||||
"AdminGroup": "ENTERPRISE\\Администраторы 1С"
|
||||
},
|
||||
"WebDistributiveLocation": {
|
||||
"Catalog": "",
|
||||
"x64tox86": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"outputFileName": "wwwroot/js/site.min.js",
|
||||
"inputFiles": [
|
||||
"wwwroot/js/site.js"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
///<binding BeforeBuild='Update all files' />
|
||||
@@ -0,0 +1,186 @@
|
||||
{
|
||||
"version": "1.0",
|
||||
"defaultProvider": "cdnjs",
|
||||
"libraries": [
|
||||
{
|
||||
"provider": "unpkg",
|
||||
"library": "bootstrap@4.5.0",
|
||||
"destination": "wwwroot/lib/bootstrap/",
|
||||
"files": [
|
||||
"dist/css/bootstrap-grid.css",
|
||||
"dist/css/bootstrap-grid.css.map",
|
||||
"dist/css/bootstrap-grid.min.css",
|
||||
"dist/css/bootstrap-grid.min.css.map",
|
||||
"dist/css/bootstrap-reboot.css",
|
||||
"dist/css/bootstrap-reboot.css.map",
|
||||
"dist/css/bootstrap-reboot.min.css",
|
||||
"dist/css/bootstrap-reboot.min.css.map",
|
||||
"dist/css/bootstrap.css",
|
||||
"dist/css/bootstrap.css.map",
|
||||
"dist/css/bootstrap.min.css",
|
||||
"dist/css/bootstrap.min.css.map",
|
||||
"dist/js/bootstrap.bundle.js",
|
||||
"dist/js/bootstrap.bundle.js.map",
|
||||
"dist/js/bootstrap.bundle.min.js",
|
||||
"dist/js/bootstrap.bundle.min.js.map",
|
||||
"dist/js/bootstrap.js",
|
||||
"dist/js/bootstrap.js.map",
|
||||
"dist/js/bootstrap.min.js",
|
||||
"dist/js/bootstrap.min.js.map"
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider": "unpkg",
|
||||
"library": "jquery@3.5.1",
|
||||
"destination": "wwwroot/lib/jquery/",
|
||||
"files": [
|
||||
"dist/jquery.js",
|
||||
"dist/jquery.min.js",
|
||||
"dist/jquery.min.map",
|
||||
"dist/jquery.slim.js",
|
||||
"dist/jquery.slim.min.js",
|
||||
"dist/jquery.slim.min.map"
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider": "unpkg",
|
||||
"library": "jquery-validation@1.19.2",
|
||||
"destination": "wwwroot/lib/jquery-validation/",
|
||||
"files": [
|
||||
"dist/localization/messages_ar.js",
|
||||
"dist/localization/messages_ar.min.js",
|
||||
"dist/localization/messages_az.js",
|
||||
"dist/localization/messages_az.min.js",
|
||||
"dist/localization/messages_bg.js",
|
||||
"dist/localization/messages_bg.min.js",
|
||||
"dist/localization/messages_bn_BD.js",
|
||||
"dist/localization/messages_bn_BD.min.js",
|
||||
"dist/localization/messages_ca.js",
|
||||
"dist/localization/messages_ca.min.js",
|
||||
"dist/localization/messages_cs.js",
|
||||
"dist/localization/messages_cs.min.js",
|
||||
"dist/localization/messages_da.js",
|
||||
"dist/localization/messages_da.min.js",
|
||||
"dist/localization/messages_de.js",
|
||||
"dist/localization/messages_de.min.js",
|
||||
"dist/localization/messages_el.js",
|
||||
"dist/localization/messages_el.min.js",
|
||||
"dist/localization/messages_es.js",
|
||||
"dist/localization/messages_es.min.js",
|
||||
"dist/localization/messages_es_AR.js",
|
||||
"dist/localization/messages_es_AR.min.js",
|
||||
"dist/localization/messages_es_PE.js",
|
||||
"dist/localization/messages_es_PE.min.js",
|
||||
"dist/localization/messages_et.js",
|
||||
"dist/localization/messages_et.min.js",
|
||||
"dist/localization/messages_eu.js",
|
||||
"dist/localization/messages_eu.min.js",
|
||||
"dist/localization/messages_fa.js",
|
||||
"dist/localization/messages_fa.min.js",
|
||||
"dist/localization/messages_fi.js",
|
||||
"dist/localization/messages_fi.min.js",
|
||||
"dist/localization/messages_fr.js",
|
||||
"dist/localization/messages_fr.min.js",
|
||||
"dist/localization/messages_ge.js",
|
||||
"dist/localization/messages_ge.min.js",
|
||||
"dist/localization/messages_gl.js",
|
||||
"dist/localization/messages_gl.min.js",
|
||||
"dist/localization/messages_he.js",
|
||||
"dist/localization/messages_he.min.js",
|
||||
"dist/localization/messages_hr.js",
|
||||
"dist/localization/messages_hr.min.js",
|
||||
"dist/localization/messages_hu.js",
|
||||
"dist/localization/messages_hu.min.js",
|
||||
"dist/localization/messages_hy_AM.js",
|
||||
"dist/localization/messages_hy_AM.min.js",
|
||||
"dist/localization/messages_id.js",
|
||||
"dist/localization/messages_id.min.js",
|
||||
"dist/localization/messages_is.js",
|
||||
"dist/localization/messages_is.min.js",
|
||||
"dist/localization/messages_it.js",
|
||||
"dist/localization/messages_it.min.js",
|
||||
"dist/localization/messages_ja.js",
|
||||
"dist/localization/messages_ja.min.js",
|
||||
"dist/localization/messages_ka.js",
|
||||
"dist/localization/messages_ka.min.js",
|
||||
"dist/localization/messages_kk.js",
|
||||
"dist/localization/messages_kk.min.js",
|
||||
"dist/localization/messages_ko.js",
|
||||
"dist/localization/messages_ko.min.js",
|
||||
"dist/localization/messages_lt.js",
|
||||
"dist/localization/messages_lt.min.js",
|
||||
"dist/localization/messages_lv.js",
|
||||
"dist/localization/messages_lv.min.js",
|
||||
"dist/localization/messages_mk.js",
|
||||
"dist/localization/messages_mk.min.js",
|
||||
"dist/localization/messages_my.js",
|
||||
"dist/localization/messages_my.min.js",
|
||||
"dist/localization/messages_nl.js",
|
||||
"dist/localization/messages_nl.min.js",
|
||||
"dist/localization/messages_no.js",
|
||||
"dist/localization/messages_no.min.js",
|
||||
"dist/localization/messages_pl.js",
|
||||
"dist/localization/messages_pl.min.js",
|
||||
"dist/localization/messages_pt_BR.js",
|
||||
"dist/localization/messages_pt_BR.min.js",
|
||||
"dist/localization/messages_pt_PT.js",
|
||||
"dist/localization/messages_pt_PT.min.js",
|
||||
"dist/localization/messages_ro.js",
|
||||
"dist/localization/messages_ro.min.js",
|
||||
"dist/localization/messages_ru.js",
|
||||
"dist/localization/messages_ru.min.js",
|
||||
"dist/localization/messages_sd.js",
|
||||
"dist/localization/messages_sd.min.js",
|
||||
"dist/localization/messages_si.js",
|
||||
"dist/localization/messages_si.min.js",
|
||||
"dist/localization/messages_sk.js",
|
||||
"dist/localization/messages_sk.min.js",
|
||||
"dist/localization/messages_sl.js",
|
||||
"dist/localization/messages_sl.min.js",
|
||||
"dist/localization/messages_sr.js",
|
||||
"dist/localization/messages_sr.min.js",
|
||||
"dist/localization/messages_sr_lat.js",
|
||||
"dist/localization/messages_sr_lat.min.js",
|
||||
"dist/localization/messages_sv.js",
|
||||
"dist/localization/messages_sv.min.js",
|
||||
"dist/localization/messages_th.js",
|
||||
"dist/localization/messages_th.min.js",
|
||||
"dist/localization/messages_tj.js",
|
||||
"dist/localization/messages_tj.min.js",
|
||||
"dist/localization/messages_tr.js",
|
||||
"dist/localization/messages_tr.min.js",
|
||||
"dist/localization/messages_uk.js",
|
||||
"dist/localization/messages_uk.min.js",
|
||||
"dist/localization/messages_ur.js",
|
||||
"dist/localization/messages_ur.min.js",
|
||||
"dist/localization/messages_vi.js",
|
||||
"dist/localization/messages_vi.min.js",
|
||||
"dist/localization/messages_zh.js",
|
||||
"dist/localization/messages_zh.min.js",
|
||||
"dist/localization/messages_zh_TW.js",
|
||||
"dist/localization/messages_zh_TW.min.js",
|
||||
"dist/localization/methods_de.js",
|
||||
"dist/localization/methods_de.min.js",
|
||||
"dist/localization/methods_es_CL.js",
|
||||
"dist/localization/methods_es_CL.min.js",
|
||||
"dist/localization/methods_fi.js",
|
||||
"dist/localization/methods_fi.min.js",
|
||||
"dist/localization/methods_it.js",
|
||||
"dist/localization/methods_it.min.js",
|
||||
"dist/localization/methods_nl.js",
|
||||
"dist/localization/methods_nl.min.js",
|
||||
"dist/localization/methods_pt.js",
|
||||
"dist/localization/methods_pt.min.js",
|
||||
"dist/additional-methods.js",
|
||||
"dist/additional-methods.min.js",
|
||||
"dist/jquery.validate.js",
|
||||
"dist/jquery.validate.min.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"provider": "unpkg",
|
||||
"library": "jquery-validation-unobtrusive@3.2.11",
|
||||
"destination": "wwwroot/lib/jquery-validation-unobtrusive/"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "asp.net",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"name": "asp.net",
|
||||
"private": true,
|
||||
"devDependencies": {},
|
||||
"dependencies": {}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
|
||||
for details on configuring this project to bundle and minify static web assets. */
|
||||
|
||||
a.navbar-brand {
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Provide sufficient contrast against white background */
|
||||
a {
|
||||
color: #0366d6;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
|
||||
color: #fff;
|
||||
background-color: #1b6ec2;
|
||||
border-color: #1861ac;
|
||||
}
|
||||
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
html {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.table-sm-sm th,
|
||||
.table-sm-sm td {
|
||||
padding: .3em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.border-top {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
.border-bottom {
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
button.accept-policy {
|
||||
font-size: 1rem;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
html {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
line-height: 60px; /* Vertically center the text there */
|
||||
}
|
||||
|
||||
.align-center-screen {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.no-padding {
|
||||
padding-left: 0!important;
|
||||
padding-right: 0!important;
|
||||
}
|
||||
|
||||
.table th {
|
||||
text-align: center !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.table td {
|
||||
text-align: center !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:first-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:first-child * {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:last-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:last-child * {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:not(:last-child):not(:first-child) {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:not(:last-child):not(:first-child) * {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.vertical-input-group .input-group:not(:first-child) * {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.nav-item-right-padding {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.nav-command-panel {
|
||||
|
||||
}
|
||||
|
||||
.nav-command-panel li:not(:last-child) {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.actions-column {
|
||||
|
||||
}
|
||||
|
||||
.actions-column a:not(:first-child) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.actions-column a:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
@@ -0,0 +1,399 @@
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = function (d, b) {
|
||||
extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return extendStatics(d, b);
|
||||
};
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();
|
||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
||||
return new (P || (P = Promise))(function (resolve, reject) {
|
||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||
});
|
||||
};
|
||||
var __generator = (this && this.__generator) || function (thisArg, body) {
|
||||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
||||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
||||
function verb(n) { return function (v) { return step([n, v]); }; }
|
||||
function step(op) {
|
||||
if (f) throw new TypeError("Generator is already executing.");
|
||||
while (_) try {
|
||||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
||||
if (y = 0, t) op = [op[0] & 2, t.value];
|
||||
switch (op[0]) {
|
||||
case 0: case 1: t = op; break;
|
||||
case 4: _.label++; return { value: op[1], done: false };
|
||||
case 5: _.label++; y = op[1]; op = [0]; continue;
|
||||
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
||||
default:
|
||||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
||||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
||||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
||||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
||||
if (t[2]) _.ops.pop();
|
||||
_.trys.pop(); continue;
|
||||
}
|
||||
op = body.call(thisArg, _);
|
||||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
||||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
||||
}
|
||||
};
|
||||
var Common;
|
||||
(function (Common) {
|
||||
var ItemViewModel = /** @class */ (function () {
|
||||
function ItemViewModel() {
|
||||
}
|
||||
return ItemViewModel;
|
||||
}());
|
||||
Common.ItemViewModel = ItemViewModel;
|
||||
function setAddButtonAvailability(select, addButton) {
|
||||
if ($(select).children().length > 0) {
|
||||
$(addButton).removeClass('disabled')
|
||||
.prop('disabled', false);
|
||||
}
|
||||
else {
|
||||
$(addButton).addClass('disabled')
|
||||
.prop('disabled', true);
|
||||
}
|
||||
}
|
||||
function removeOption(select, addButton, value) {
|
||||
$(select).children('option').each(function (index, elem) {
|
||||
if ($(elem).val() == value) {
|
||||
$(elem).remove();
|
||||
}
|
||||
});
|
||||
setAddButtonAvailability(select, addButton);
|
||||
}
|
||||
function addOption(select, addButton, text, value) {
|
||||
var option = document.createElement('option');
|
||||
$(option).val(value)
|
||||
.text(text)
|
||||
.appendTo(select);
|
||||
setAddButtonAvailability(select, addButton);
|
||||
}
|
||||
function removeRow(select, table, addButton, deleteButton) {
|
||||
var text;
|
||||
var value;
|
||||
var tr = $(deleteButton).closest('tr');
|
||||
var idInput = $(tr).find(':input:hidden').first();
|
||||
value = idInput.val();
|
||||
text = idInput.closest('td').text();
|
||||
tr.remove();
|
||||
addOption(select, addButton, text, value);
|
||||
}
|
||||
function addRow(select, table, addButton) {
|
||||
var selectedIndex = $(select).prop('selectedIndex');
|
||||
var selectedItem = $(select).children().eq(selectedIndex);
|
||||
var value = $(selectedItem).val();
|
||||
var label = $(selectedItem).text();
|
||||
var tbody = $(table).find('tbody');
|
||||
var tableId = $(table).attr('id');
|
||||
var row = document.createElement('tr');
|
||||
$(row).appendTo(tbody);
|
||||
var col1 = document.createElement('td');
|
||||
$(col1).text(label)
|
||||
.appendTo(row);
|
||||
var inputName = document.createElement('input');
|
||||
$(inputName).val(value)
|
||||
.attr('type', 'hidden')
|
||||
.attr('name', "" + tableId)
|
||||
.appendTo(col1);
|
||||
var col2 = document.createElement('td');
|
||||
$(col2).appendTo(row);
|
||||
var deleteBtn = document.createElement('button');
|
||||
$(deleteBtn).attr('type', 'button')
|
||||
.addClass('btn btn-danger')
|
||||
.click(function (event) {
|
||||
removeRow(select, table, addButton, event.currentTarget);
|
||||
})
|
||||
.appendTo(col2);
|
||||
var deleteI = document.createElement('i');
|
||||
$(deleteI).addClass('fa fa-trash')
|
||||
.appendTo(deleteBtn);
|
||||
removeOption(select, addButton, value);
|
||||
}
|
||||
function connectSelectToTable(select, addButton, table) {
|
||||
setAddButtonAvailability(select, addButton);
|
||||
$(addButton).click(function () {
|
||||
addRow(select, table, addButton);
|
||||
});
|
||||
$(table).find('.fa-trash').each(function (index, elem) {
|
||||
$(elem).closest('button').click(function () {
|
||||
return removeRow(select, table, addButton, elem);
|
||||
});
|
||||
});
|
||||
}
|
||||
Common.connectSelectToTable = connectSelectToTable;
|
||||
})(Common || (Common = {}));
|
||||
var InfoBases;
|
||||
(function (InfoBases) {
|
||||
var InfoBaseItemViewModel = /** @class */ (function (_super) {
|
||||
__extends(InfoBaseItemViewModel, _super);
|
||||
function InfoBaseItemViewModel() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return InfoBaseItemViewModel;
|
||||
}(Common.ItemViewModel));
|
||||
InfoBases.InfoBaseItemViewModel = InfoBaseItemViewModel;
|
||||
var InfoBaseViewModel = /** @class */ (function () {
|
||||
function InfoBaseViewModel() {
|
||||
}
|
||||
return InfoBaseViewModel;
|
||||
}());
|
||||
InfoBases.InfoBaseViewModel = InfoBaseViewModel;
|
||||
var InfoBaseIndexViewModel = /** @class */ (function () {
|
||||
function InfoBaseIndexViewModel() {
|
||||
}
|
||||
return InfoBaseIndexViewModel;
|
||||
}());
|
||||
InfoBases.InfoBaseIndexViewModel = InfoBaseIndexViewModel;
|
||||
function showFormGroupFor(elem) {
|
||||
$(elem).closest('.form-group')
|
||||
.show();
|
||||
}
|
||||
function hideFormGroupFor(elem) {
|
||||
$(elem).val('')
|
||||
.closest('.form-group')
|
||||
.hide();
|
||||
}
|
||||
function setGroupsVisibility() {
|
||||
var select = $('#ConnectionType');
|
||||
var selectedIndex = $(select).prop('selectedIndex');
|
||||
var value = $(select).children().eq(selectedIndex).val();
|
||||
switch (value) {
|
||||
case "0":
|
||||
showFormGroupFor($('#Path'));
|
||||
hideFormGroupFor($('#URL'));
|
||||
hideFormGroupFor($('#Server'));
|
||||
hideFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
case "1":
|
||||
hideFormGroupFor($('#Path'));
|
||||
hideFormGroupFor($('#URL'));
|
||||
showFormGroupFor($('#Server'));
|
||||
showFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
case "2":
|
||||
hideFormGroupFor($('#Path'));
|
||||
showFormGroupFor($('#URL'));
|
||||
hideFormGroupFor($('#Server'));
|
||||
hideFormGroupFor($('#InfoBaseName'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
function initInfoBaseCreateEditView() {
|
||||
setGroupsVisibility();
|
||||
$('#ConnectionType').change(function (e, t) {
|
||||
setGroupsVisibility();
|
||||
});
|
||||
}
|
||||
InfoBases.initInfoBaseCreateEditView = initInfoBaseCreateEditView;
|
||||
})(InfoBases || (InfoBases = {}));
|
||||
var InfoBasesLists;
|
||||
(function (InfoBasesLists) {
|
||||
var InfoBasesListItemViewModel = /** @class */ (function (_super) {
|
||||
__extends(InfoBasesListItemViewModel, _super);
|
||||
function InfoBasesListItemViewModel() {
|
||||
return _super !== null && _super.apply(this, arguments) || this;
|
||||
}
|
||||
return InfoBasesListItemViewModel;
|
||||
}(Common.ItemViewModel));
|
||||
InfoBasesLists.InfoBasesListItemViewModel = InfoBasesListItemViewModel;
|
||||
var InfoBasesListViewModel = /** @class */ (function () {
|
||||
function InfoBasesListViewModel() {
|
||||
}
|
||||
return InfoBasesListViewModel;
|
||||
}());
|
||||
InfoBasesLists.InfoBasesListViewModel = InfoBasesListViewModel;
|
||||
var InfoBasesListIndexViewModel = /** @class */ (function () {
|
||||
function InfoBasesListIndexViewModel() {
|
||||
}
|
||||
return InfoBasesListIndexViewModel;
|
||||
}());
|
||||
InfoBasesLists.InfoBasesListIndexViewModel = InfoBasesListIndexViewModel;
|
||||
})(InfoBasesLists || (InfoBasesLists = {}));
|
||||
var Users;
|
||||
(function (Users) {
|
||||
var UserViewModel = /** @class */ (function () {
|
||||
function UserViewModel() {
|
||||
}
|
||||
return UserViewModel;
|
||||
}());
|
||||
Users.UserViewModel = UserViewModel;
|
||||
var UserIndexViewModel = /** @class */ (function () {
|
||||
function UserIndexViewModel() {
|
||||
}
|
||||
return UserIndexViewModel;
|
||||
}());
|
||||
Users.UserIndexViewModel = UserIndexViewModel;
|
||||
function updateFromActiveDirectory() {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var btn, response;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
btn = $('#updateFromAd');
|
||||
btn.addClass('disabled')
|
||||
.prop('disabled', true);
|
||||
return [4 /*yield*/, fetch('/Users/UpdateFromActiveDirectory')];
|
||||
case 1:
|
||||
response = _a.sent();
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
}
|
||||
else {
|
||||
alert('Не удалось обновить список пользователей');
|
||||
}
|
||||
btn.removeClass('disabled')
|
||||
.prop('disabled', false);
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Users.updateFromActiveDirectory = updateFromActiveDirectory;
|
||||
function initIndexView() {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var url, time;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
url = '/Users/GetUsers';
|
||||
return [4 /*yield*/, getUsers(url, 1, '')];
|
||||
case 1:
|
||||
_a.sent();
|
||||
time = 0;
|
||||
$('#searchBox').keyup(function (event) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
clearTimeout(time);
|
||||
time = window.setTimeout(function () {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var term;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
term = $('#searchBox').val();
|
||||
return [4 /*yield*/, getUsers(url, 1, term)];
|
||||
case 1:
|
||||
_a.sent();
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 500);
|
||||
return [2 /*return*/];
|
||||
});
|
||||
});
|
||||
});
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
Users.initIndexView = initIndexView;
|
||||
function getUsers(url, pageIndex, term) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
var urlParams, response, data;
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
urlParams = url + "?pageIndex=" + pageIndex;
|
||||
if (term != '')
|
||||
urlParams += "&term=" + term;
|
||||
return [4 /*yield*/, fetch(urlParams)];
|
||||
case 1:
|
||||
response = _a.sent();
|
||||
if (!response.ok) return [3 /*break*/, 3];
|
||||
return [4 /*yield*/, response.json()];
|
||||
case 2:
|
||||
data = _a.sent();
|
||||
fillUsersTable(data);
|
||||
fillUsersPagesNav(data, url, term);
|
||||
return [3 /*break*/, 4];
|
||||
case 3:
|
||||
alert('Не удалось получить список пользователей');
|
||||
_a.label = 4;
|
||||
case 4: return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function fillUsersTable(userIndexViewModel) {
|
||||
var tbody = $('#dataTable').children('tbody').first().empty();
|
||||
userIndexViewModel.items.forEach(function (value) {
|
||||
var tr = document.createElement('tr');
|
||||
$(tr).appendTo(tbody);
|
||||
var tdName = document.createElement('td');
|
||||
$(tdName).text(value.name)
|
||||
.appendTo(tr);
|
||||
var tdSamAccountName = document.createElement('td');
|
||||
$(tdSamAccountName).text(value.samAccountName)
|
||||
.appendTo(tr);
|
||||
var tdInfoBasesListName = document.createElement('td');
|
||||
$(tdInfoBasesListName).appendTo(tr);
|
||||
if (value.infoBasesList != null)
|
||||
$(tdInfoBasesListName).text(value.infoBasesList.name);
|
||||
var tdActions = document.createElement('td');
|
||||
$(tdActions).appendTo(tr);
|
||||
var aEdit = document.createElement('a');
|
||||
$(aEdit).addClass('btn btn-secondary col-auto m-1')
|
||||
.attr('href', "/Users/Edit/" + value.id)
|
||||
.appendTo(tdActions);
|
||||
var iEdit = document.createElement('i');
|
||||
$(iEdit).addClass('fa fa-edit')
|
||||
.appendTo(aEdit);
|
||||
var aDelete = document.createElement('a');
|
||||
$(aDelete).addClass('btn btn-danger col-auto m-1')
|
||||
.attr('href', "/Users/Delete/" + value.id)
|
||||
.appendTo(tdActions);
|
||||
var iDelete = document.createElement('i');
|
||||
$(iDelete).addClass('fa fa-trash')
|
||||
.appendTo(aDelete);
|
||||
});
|
||||
}
|
||||
function fillUsersPagesNav(userIndexViewModel, url, term) {
|
||||
var ul = $('#pagesNav').children('ul').first().empty();
|
||||
if (userIndexViewModel.pagesAmount > 1) {
|
||||
var _loop_1 = function (i) {
|
||||
var li = document.createElement('li');
|
||||
$(li).addClass('page-item')
|
||||
.appendTo(ul);
|
||||
if (i === userIndexViewModel.currentPage)
|
||||
$(li).addClass('active');
|
||||
var a = document.createElement('a');
|
||||
$(a).text(i)
|
||||
.attr('href', '#')
|
||||
.addClass('page-link')
|
||||
.click(function () {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0: return [4 /*yield*/, getUsers(url, i, term)];
|
||||
case 1:
|
||||
_a.sent();
|
||||
return [2 /*return*/];
|
||||
}
|
||||
});
|
||||
});
|
||||
})
|
||||
.appendTo(li);
|
||||
};
|
||||
for (var i = 1; i <= userIndexViewModel.pagesAmount; i++) {
|
||||
_loop_1(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
})(Users || (Users = {}));
|
||||
//# sourceMappingURL=site.js.map
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,325 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.5.0 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2020 The Bootstrap Authors
|
||||
* Copyright 2011-2020 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus:not(:focus-visible) {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
-webkit-text-decoration-skip-ink: none;
|
||||
text-decoration-skip-ink: none;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):hover {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
overflow: hidden;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
[role="button"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
select {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
button,
|
||||
[type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button:not(:disabled),
|
||||
[type="button"]:not(:disabled),
|
||||
[type="reset"]:not(:disabled),
|
||||
[type="submit"]:not(:disabled) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.5.0 (https://getbootstrap.com/)
|
||||
* Copyright 2011-2020 The Bootstrap Authors
|
||||
* Copyright 2011-2020 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
||||
File diff suppressed because one or more lines are too long
+10278
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4420
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,34 @@
|
||||
Font Awesome Free License
|
||||
-------------------------
|
||||
|
||||
Font Awesome Free is free, open source, and GPL friendly. You can use it for
|
||||
commercial projects, open source projects, or really almost whatever you want.
|
||||
Full Font Awesome Free license: https://fontawesome.com/license/free.
|
||||
|
||||
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
|
||||
In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
|
||||
packaged as SVG and JS file types.
|
||||
|
||||
# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
|
||||
In the Font Awesome Free download, the SIL OFL license applies to all icons
|
||||
packaged as web and desktop font files.
|
||||
|
||||
# Code: MIT License (https://opensource.org/licenses/MIT)
|
||||
In the Font Awesome Free download, the MIT license applies to all non-font and
|
||||
non-icon files.
|
||||
|
||||
# Attribution
|
||||
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
|
||||
Awesome Free files already contain embedded comments with sufficient
|
||||
attribution, so you shouldn't need to do anything additional when using these
|
||||
files normally.
|
||||
|
||||
We've kept attribution comments terse, so we ask that you do not actively work
|
||||
to remove them from files, especially code. They're a great way for folks to
|
||||
learn about Font Awesome.
|
||||
|
||||
# Brand Icons
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Brands';
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-display: auto;
|
||||
src: url("../webfonts/fa-brands-400.eot");
|
||||
src: url("../webfonts/fa-brands-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.woff") format("woff"), url("../webfonts/fa-brands-400.ttf") format("truetype"), url("../webfonts/fa-brands-400.svg#fontawesome") format("svg"); }
|
||||
|
||||
.fab {
|
||||
font-family: 'Font Awesome 5 Brands'; }
|
||||
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,15 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: auto;
|
||||
src: url("../webfonts/fa-regular-400.eot");
|
||||
src: url("../webfonts/fa-regular-400.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.woff") format("woff"), url("../webfonts/fa-regular-400.ttf") format("truetype"), url("../webfonts/fa-regular-400.svg#fontawesome") format("svg"); }
|
||||
|
||||
.far {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-weight: 400; }
|
||||
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-family:"Font Awesome 5 Free";font-weight:400}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: auto;
|
||||
src: url("../webfonts/fa-solid-900.eot");
|
||||
src: url("../webfonts/fa-solid-900.eot?#iefix") format("embedded-opentype"), url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.woff") format("woff"), url("../webfonts/fa-solid-900.ttf") format("truetype"), url("../webfonts/fa-solid-900.svg#fontawesome") format("svg"); }
|
||||
|
||||
.fa,
|
||||
.fas {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-weight: 900; }
|
||||
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900}
|
||||
@@ -0,0 +1,371 @@
|
||||
/*!
|
||||
* Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
*/
|
||||
svg:not(:root).svg-inline--fa {
|
||||
overflow: visible; }
|
||||
|
||||
.svg-inline--fa {
|
||||
display: inline-block;
|
||||
font-size: inherit;
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -.125em; }
|
||||
.svg-inline--fa.fa-lg {
|
||||
vertical-align: -.225em; }
|
||||
.svg-inline--fa.fa-w-1 {
|
||||
width: 0.0625em; }
|
||||
.svg-inline--fa.fa-w-2 {
|
||||
width: 0.125em; }
|
||||
.svg-inline--fa.fa-w-3 {
|
||||
width: 0.1875em; }
|
||||
.svg-inline--fa.fa-w-4 {
|
||||
width: 0.25em; }
|
||||
.svg-inline--fa.fa-w-5 {
|
||||
width: 0.3125em; }
|
||||
.svg-inline--fa.fa-w-6 {
|
||||
width: 0.375em; }
|
||||
.svg-inline--fa.fa-w-7 {
|
||||
width: 0.4375em; }
|
||||
.svg-inline--fa.fa-w-8 {
|
||||
width: 0.5em; }
|
||||
.svg-inline--fa.fa-w-9 {
|
||||
width: 0.5625em; }
|
||||
.svg-inline--fa.fa-w-10 {
|
||||
width: 0.625em; }
|
||||
.svg-inline--fa.fa-w-11 {
|
||||
width: 0.6875em; }
|
||||
.svg-inline--fa.fa-w-12 {
|
||||
width: 0.75em; }
|
||||
.svg-inline--fa.fa-w-13 {
|
||||
width: 0.8125em; }
|
||||
.svg-inline--fa.fa-w-14 {
|
||||
width: 0.875em; }
|
||||
.svg-inline--fa.fa-w-15 {
|
||||
width: 0.9375em; }
|
||||
.svg-inline--fa.fa-w-16 {
|
||||
width: 1em; }
|
||||
.svg-inline--fa.fa-w-17 {
|
||||
width: 1.0625em; }
|
||||
.svg-inline--fa.fa-w-18 {
|
||||
width: 1.125em; }
|
||||
.svg-inline--fa.fa-w-19 {
|
||||
width: 1.1875em; }
|
||||
.svg-inline--fa.fa-w-20 {
|
||||
width: 1.25em; }
|
||||
.svg-inline--fa.fa-pull-left {
|
||||
margin-right: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-pull-right {
|
||||
margin-left: .3em;
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-border {
|
||||
height: 1.5em; }
|
||||
.svg-inline--fa.fa-li {
|
||||
width: 2em; }
|
||||
.svg-inline--fa.fa-fw {
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.fa-layers {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: -.125em;
|
||||
width: 1em; }
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-text, .fa-layers-counter {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
|
||||
.fa-layers-text {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-counter {
|
||||
background-color: #ff253a;
|
||||
border-radius: 1em;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
height: 1.5em;
|
||||
line-height: 1;
|
||||
max-width: 5em;
|
||||
min-width: 1.5em;
|
||||
overflow: hidden;
|
||||
padding: .25em;
|
||||
right: 0;
|
||||
text-overflow: ellipsis;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-bottom-right {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom right;
|
||||
transform-origin: bottom right; }
|
||||
|
||||
.fa-layers-bottom-left {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: auto;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: bottom left;
|
||||
transform-origin: bottom left; }
|
||||
|
||||
.fa-layers-top-right {
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-top-left {
|
||||
left: 0;
|
||||
right: auto;
|
||||
top: 0;
|
||||
-webkit-transform: scale(0.25);
|
||||
transform: scale(0.25);
|
||||
-webkit-transform-origin: top left;
|
||||
transform-origin: top left; }
|
||||
|
||||
.fa-lg {
|
||||
font-size: 1.33333em;
|
||||
line-height: 0.75em;
|
||||
vertical-align: -.0667em; }
|
||||
|
||||
.fa-xs {
|
||||
font-size: .75em; }
|
||||
|
||||
.fa-sm {
|
||||
font-size: .875em; }
|
||||
|
||||
.fa-1x {
|
||||
font-size: 1em; }
|
||||
|
||||
.fa-2x {
|
||||
font-size: 2em; }
|
||||
|
||||
.fa-3x {
|
||||
font-size: 3em; }
|
||||
|
||||
.fa-4x {
|
||||
font-size: 4em; }
|
||||
|
||||
.fa-5x {
|
||||
font-size: 5em; }
|
||||
|
||||
.fa-6x {
|
||||
font-size: 6em; }
|
||||
|
||||
.fa-7x {
|
||||
font-size: 7em; }
|
||||
|
||||
.fa-8x {
|
||||
font-size: 8em; }
|
||||
|
||||
.fa-9x {
|
||||
font-size: 9em; }
|
||||
|
||||
.fa-10x {
|
||||
font-size: 10em; }
|
||||
|
||||
.fa-fw {
|
||||
text-align: center;
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-ul {
|
||||
list-style-type: none;
|
||||
margin-left: 2.5em;
|
||||
padding-left: 0; }
|
||||
.fa-ul > li {
|
||||
position: relative; }
|
||||
|
||||
.fa-li {
|
||||
left: -2em;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 2em;
|
||||
line-height: inherit; }
|
||||
|
||||
.fa-border {
|
||||
border: solid 0.08em #eee;
|
||||
border-radius: .1em;
|
||||
padding: .2em .25em .15em; }
|
||||
|
||||
.fa-pull-left {
|
||||
float: left; }
|
||||
|
||||
.fa-pull-right {
|
||||
float: right; }
|
||||
|
||||
.fa.fa-pull-left,
|
||||
.fas.fa-pull-left,
|
||||
.far.fa-pull-left,
|
||||
.fal.fa-pull-left,
|
||||
.fab.fa-pull-left {
|
||||
margin-right: .3em; }
|
||||
|
||||
.fa.fa-pull-right,
|
||||
.fas.fa-pull-right,
|
||||
.far.fa-pull-right,
|
||||
.fal.fa-pull-right,
|
||||
.fab.fa-pull-right {
|
||||
margin-left: .3em; }
|
||||
|
||||
.fa-spin {
|
||||
-webkit-animation: fa-spin 2s infinite linear;
|
||||
animation: fa-spin 2s infinite linear; }
|
||||
|
||||
.fa-pulse {
|
||||
-webkit-animation: fa-spin 1s infinite steps(8);
|
||||
animation: fa-spin 1s infinite steps(8); }
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.fa-rotate-90 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg); }
|
||||
|
||||
.fa-rotate-180 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg); }
|
||||
|
||||
.fa-rotate-270 {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg); }
|
||||
|
||||
.fa-flip-horizontal {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";
|
||||
-webkit-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1); }
|
||||
|
||||
.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(1, -1);
|
||||
transform: scale(1, -1); }
|
||||
|
||||
.fa-flip-both, .fa-flip-horizontal.fa-flip-vertical {
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";
|
||||
-webkit-transform: scale(-1, -1);
|
||||
transform: scale(-1, -1); }
|
||||
|
||||
:root .fa-rotate-90,
|
||||
:root .fa-rotate-180,
|
||||
:root .fa-rotate-270,
|
||||
:root .fa-flip-horizontal,
|
||||
:root .fa-flip-vertical,
|
||||
:root .fa-flip-both {
|
||||
-webkit-filter: none;
|
||||
filter: none; }
|
||||
|
||||
.fa-stack {
|
||||
display: inline-block;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-stack-1x,
|
||||
.fa-stack-2x {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.svg-inline--fa.fa-stack-1x {
|
||||
height: 1em;
|
||||
width: 1.25em; }
|
||||
|
||||
.svg-inline--fa.fa-stack-2x {
|
||||
height: 2em;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-inverse {
|
||||
color: #fff; }
|
||||
|
||||
.sr-only {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px; }
|
||||
|
||||
.sr-only-focusable:active, .sr-only-focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
width: auto; }
|
||||
|
||||
.svg-inline--fa .fa-primary {
|
||||
fill: var(--fa-primary-color, currentColor);
|
||||
opacity: 1;
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa .fa-secondary {
|
||||
fill: var(--fa-secondary-color, currentColor);
|
||||
opacity: 0.4;
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||
opacity: 0.4;
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||
opacity: 1;
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa mask .fa-primary,
|
||||
.svg-inline--fa mask .fa-secondary {
|
||||
fill: black; }
|
||||
|
||||
.fad.fa-inverse {
|
||||
color: #fff; }
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user