1
0

Updated site

This commit is contained in:
Michael Gordeev
2020-03-12 22:01:12 +03:00
parent 1e6aea6b17
commit 17bdf1ea77
97 changed files with 88723 additions and 3602 deletions
@@ -7,38 +7,38 @@ using MyWebsite.Models.Databases;
namespace MyWebsite.Areas.API
{
[ApiController]
[Route("API/[controller]")]
public class FoxTubeController : ControllerBase
{
readonly FoxTubeDatabaseContext db;
public FoxTubeController(FoxTubeDatabaseContext context) =>
db = context;
[ApiController]
[Route("API/[controller]")]
public class FoxTubeController : ControllerBase
{
readonly FoxTubeDatabaseContext db;
public FoxTubeController(FoxTubeDatabaseContext context) =>
db = context;
[HttpPost]
[Route("AddMetrics")]
public IActionResult AddMetrics(MetricsPackage package)
{
Guid id = db.Metrics.Add(package).Entity.Id;
db.SaveChanges();
[HttpPost]
[Route("AddMetrics")]
public IActionResult AddMetrics(MetricsPackage package)
{
Guid id = db.Metrics.Add(package).Entity.Id;
db.SaveChanges();
return Accepted(value: id.ToString());
}
return Accepted(value: id.ToString());
}
[HttpGet]
[Route("Messages")]
public IActionResult Messages(bool toast = false, DateTime? publishedAfter = null, string lang = "en-US")
{
if (toast)
{
Message message = publishedAfter.HasValue ?
db.Messages.FirstOrDefault(i => i.PublishedAt >= publishedAfter && i.PublishedAt <= DateTime.Now && i.Language == lang) :
db.Messages.OrderByDescending(i => i.PublishedAt).FirstOrDefault();
[HttpGet]
[Route("Messages")]
public IActionResult Messages(bool toast = false, DateTime? publishedAfter = null, string lang = "en-US")
{
if (toast)
{
Message message = publishedAfter.HasValue ?
db.Messages.FirstOrDefault(i => i.PublishedAt >= publishedAfter && i.PublishedAt <= DateTime.Now && i.Language == lang) :
db.Messages.OrderByDescending(i => i.PublishedAt).FirstOrDefault();
if (message == null)
return NoContent();
if (message == null)
return NoContent();
return Ok($@"<toast activationType='foreground' launch='inbox|{message.Id}'>
return Ok($@"<toast activationType='foreground' launch='inbox|{message.Id}'>
<visual>
<binding template='ToastGeneric'>
<image placement='hero' src='{message.HeroImage}'/>
@@ -48,22 +48,22 @@ namespace MyWebsite.Areas.API
</binding>
</visual>
</toast>");
}
else
return Ok(db.Messages.Where(i => i.PublishedAt <= DateTime.Now).ToList());
}
}
else
return Ok(db.Messages.Where(i => i.PublishedAt <= DateTime.Now).ToList());
}
[HttpGet]
[Route("Changelogs")]
public IActionResult Changelogs(string version, bool toast = false, string lang = "en-US")
{
if (toast)
{
Changelog changelog = db.Changelogs.FirstOrDefault(i => i.Version == version && i.Language == lang);
if (changelog == null)
return NoContent();
[HttpGet]
[Route("Changelogs")]
public IActionResult Changelogs(string version, bool toast = false, string lang = "en-US")
{
if (toast)
{
Changelog changelog = db.Changelogs.FirstOrDefault(i => i.Version == version && i.Language == lang);
if (changelog == null)
return NoContent();
return Ok($@"<toast activationType='foreground' launch='changelog|{changelog.Id}'>
return Ok($@"<toast activationType='foreground' launch='changelog|{changelog.Id}'>
<visual>
<binding template='ToastGeneric'>
<image placement='hero' src='{changelog.HeroImage}'/>
@@ -73,17 +73,17 @@ namespace MyWebsite.Areas.API
</binding>
</visual>
</toast>");
}
else
return Ok(db.Changelogs.Where(i => !IsVersionGreater(i.Version, version)).ToList());
}
}
else
return Ok(db.Changelogs.Where(i => !IsVersionGreater(i.Version, version)).ToList());
}
private static bool IsVersionGreater(string versionOne, string versionTwo)
{
versionOne = versionOne.Replace(".", "", StringComparison.InvariantCulture);
versionTwo = versionTwo.Replace(".", "", StringComparison.InvariantCulture);
private static bool IsVersionGreater(string versionOne, string versionTwo)
{
versionOne = versionOne.Replace(".", "", StringComparison.InvariantCulture);
versionTwo = versionTwo.Replace(".", "", StringComparison.InvariantCulture);
return short.Parse(versionOne, NumberStyles.Integer, CultureInfo.InvariantCulture) > short.Parse(versionTwo, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
}
return short.Parse(versionOne, NumberStyles.Integer, CultureInfo.InvariantCulture) > short.Parse(versionTwo, NumberStyles.Integer, CultureInfo.InvariantCulture);
}
}
}
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using MyWebsite.Controllers;
using MyWebsite.Models.Databases;
using System.Linq;
namespace MyWebsite.Areas.API
{
@@ -8,10 +9,12 @@ namespace MyWebsite.Areas.API
[Route("API/[controller]")]
public class GUTScheduleController : ExtendedController
{
public GUTScheduleController(DatabaseContext context) : base(context) { }
GUTScheduleDatabaseContext databaseContext;
public GUTScheduleController(DatabaseContext context, GUTScheduleDatabaseContext db) : base(context) =>
databaseContext = db;
[Route("SemesterOffsetDay")]
public string SemesterOffsetDay() =>
Database.CustomData.Find("gut.schedule.semester.offset")?.Value ?? "undefined";
databaseContext.OffsetDates?.FirstOrDefault()?.Value ?? "undefined";
}
}
@@ -7,87 +7,116 @@ using MyWebsite.Models.Databases;
using System;
using System.Globalization;
using System.IO;
using System.Linq;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class BadgesController : ExtendedController
{
public BadgesController(DatabaseContext context) : base(context) { }
[Area("Admin")]
[Authorize]
public class BadgesController : ExtendedController
{
public BadgesController(DatabaseContext context) : base(context) { }
public IActionResult Index() =>
View(Database.Badges);
[HttpGet]
public IActionResult Index() =>
View(Database.Badges);
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Badges.Find(id));
[HttpPost]
public IActionResult Index(IFormFile badgeImage)
{
if (badgeImage == null)
throw new ArgumentNullException(nameof(badgeImage));
[HttpPost]
public IActionResult Edit(BadgeModel model, IFormFile file = null)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
System.Drawing.Image image = System.Drawing.Image.FromStream(badgeImage.OpenReadStream());
if (System.IO.File.Exists(Directory.GetCurrentDirectory() + "/wwwroot/images/Badges/" + badgeImage.FileName))
ModelState.AddModelError("Error", $"Badge image with such name ({badgeImage.FileName}) is already esists");
else if (image.Width != 64 || image.Height != 64 || !badgeImage.FileName.EndsWith(".PNG", true, CultureInfo.InvariantCulture))
ModelState.AddModelError("Error", "The file must be EXACTLY 64x64 pixels PNG image");
else
using (var stream = System.IO.File.Create(Directory.GetCurrentDirectory() + "/wwwroot/images/Badges/" + badgeImage.FileName))
badgeImage.CopyTo(stream);
if (file != null)
UploadFile(file, model);
return View(Database.Badges);
}
Database.Badges.Update(model);
Database.SaveChanges();
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Badges.Find(id));
return RedirectToAction("Index");
}
[HttpPost]
public IActionResult Edit(BadgeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Badges.Find(id));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpPost]
public IActionResult Delete(BadgeModel model)
{
Database.Badges.Remove(model);
Database.SaveChanges();
Database.Badges.Update(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Create() =>
View();
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Badges.Find(id));
[HttpPost]
public IActionResult Create(BadgeModel model, IFormFile file = null)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
[HttpPost]
public IActionResult Delete(BadgeModel model)
{
if (Database.Projects.ToList().Any(i => i.Badges.Contains(model.Name, StringComparison.InvariantCulture)))
{
ModelState.Clear();
ModelState.AddModelError("Error", "Remove badge references from projects descriptions in order to delete the badge");
return View(Database.Badges.Find(model?.Name));
}
if (file != null)
return UploadFile(file, model);
Database.Badges.Remove(model);
Database.SaveChanges();
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
return RedirectToAction("Index");
}
Database.Badges.Add(model);
Database.SaveChanges();
[HttpGet]
public IActionResult Create() =>
View(model: null);
return RedirectToAction("Index");
}
[HttpPost]
public IActionResult Create(BadgeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
private IActionResult UploadFile(IFormFile file, BadgeModel model)
{
System.Drawing.Image image = System.Drawing.Image.FromStream(file.OpenReadStream());
if (image.Width != 64 || image.Height != 64 || !file.FileName.EndsWith(".PNG", true, CultureInfo.InvariantCulture))
{
ViewData["UploadException"] = "error";
return View(model);
}
using (var stream = System.IO.File.Create(Directory.GetCurrentDirectory() + "/wwwroot/images/Badges/" + file.FileName))
file.CopyTo(stream);
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
return Redirect(Request.Path.Value);
}
}
if (Database.Badges.Any(i => i.Name == model.Name))
{
ModelState.AddModelError("Error", $"Badge '{model.Name}' is already exists");
return View(model);
}
Database.Badges.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult DeleteBadgeImage(string id)
{
string path = Directory.GetCurrentDirectory() + "/wwwroot/images/Badges/" + id;
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
return RedirectToAction("Index");
}
}
}
@@ -3,61 +3,99 @@ using Microsoft.AspNetCore.Mvc;
using MyWebsite.Controllers;
using MyWebsite.Models;
using MyWebsite.Models.Databases;
using System;
using System.Linq;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class ContactsController : ExtendedController
{
public ContactsController(DatabaseContext context) : base(context) { }
[Area("Admin")]
[Authorize]
public class ContactsController : ExtendedController
{
public ContactsController(DatabaseContext context) : base(context) { }
public IActionResult Index() =>
View(Database.Links);
public IActionResult Index() =>
View(Database.Links);
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Links.Find(id));
[HttpPost]
public IActionResult Index(string[] reorderList)
{
if(reorderList?.Length != Database.Links.Count())
{
ModelState.AddModelError("Error", "Invalid or incomplete data recieved");
return View(Database.Links);
}
[HttpPost]
public IActionResult Edit(LinkModel model)
{
Database.Links.Update(model);
Database.SaveChanges();
for (int i = 0; i < reorderList.Length; i++)
Database.Links.Find(reorderList[i]).Order = i;
Database.SaveChanges();
return RedirectToAction("Index");
}
return View(Database.Links);
}
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Links.Find(id));
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Links.Find(id));
[HttpPost]
public IActionResult Delete(LinkModel model)
{
Database.Links.Remove(model);
Database.SaveChanges();
[HttpPost]
public IActionResult Edit(LinkModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
return RedirectToAction("Index");
}
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpGet]
public IActionResult Create() =>
View();
Database.Links.Update(model);
Database.SaveChanges();
[HttpPost]
public IActionResult Create(LinkModel model)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
return RedirectToAction("Index");
}
Database.Links.Add(model);
Database.SaveChanges();
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Links.Find(id));
return RedirectToAction("Index");
}
}
[HttpPost]
public IActionResult Delete(LinkModel model)
{
Database.Links.Remove(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Create() =>
View(model: null);
[HttpPost]
public IActionResult Create(LinkModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
model.Order = Database.Links.Count();
if (Database.Links.Any(i => i.Name == model.Name))
{
ModelState.AddModelError("Error", $"Link '{model.Name}' is already exists");
return View(model);
}
Database.Links.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
}
}
@@ -2,51 +2,68 @@
using Microsoft.AspNetCore.Mvc;
using MyWebsite.Controllers;
using MyWebsite.Helpers;
using MyWebsite.Models;
using MyWebsite.Models.Databases;
using System.Linq;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class CredentialController : ExtendedController
{
const string viewPath = "Areas/Admin/Views/Shared/Credential.cshtml";
[Area("Admin")]
[Authorize]
public class CredentialController : ExtendedController
{
const string viewPath = "Areas/Admin/Views/Shared/Credential.cshtml";
public CredentialController(DatabaseContext context) : base(context) { }
public CredentialController(DatabaseContext context) : base(context) { }
[HttpGet]
public IActionResult Index() =>
View(viewPath);
[HttpGet]
public IActionResult Index() =>
View(viewPath);
[HttpPost]
public IActionResult Index(Models.CredentialModel model)
{
MyWebsite.Models.CredentialModel credential = Database.Users.FirstOrDefault();
[HttpPost]
public IActionResult Index(string key, string value)
{
if(string.IsNullOrWhiteSpace(key))
{
ModelState.AddModelError("Validation error", "Unable to identify data to update");
return View(viewPath);
}
if (model == null || model.Current.Email != credential.Email || !Encryptor.VerifyHash(model.Current.Password, credential.Password))
{
ModelState.AddModelError("Authorization error", "Invaild e-mail or password");
return View(viewPath, model);
}
if(string.IsNullOrWhiteSpace(value))
{
ModelState.AddModelError("Validation error", "No data provided");
return View(viewPath);
}
if(string.IsNullOrWhiteSpace(model.Updated.Email) && string.IsNullOrWhiteSpace(model.Current.Password))
{
ModelState.AddModelError("Validation error", "No data to update");
return View(viewPath, model);
}
CredentialModel credential = Database.Users.FirstOrDefault();
Database.Users.RemoveRange(Database.Users);
Database.Users.Remove(credential);
Database.SaveChanges();
if(!string.IsNullOrWhiteSpace(model.Current.Email))
credential.Email = model.Updated.Email;
if(!string.IsNullOrWhiteSpace(model.Current.Password))
credential.Password = Encryptor.ComputeHash(model.Updated.Password);
Database.Users.Add(credential);
switch (key)
{
case "password":
Database.Users.Add(new CredentialModel
{
Email = credential.Email,
Password = Encryptor.ComputeHash(value)
});
break;
Database.SaveChanges();
case "email":
Database.Users.Add(new CredentialModel
{
Email = value,
Password = credential.Password
});
break;
return Redirect("~/Admin/Logout");
}
}
default:
ModelState.AddModelError("Processing error", "Provided data is missing or read-only");
return View(viewPath);
}
Database.SaveChanges();
return Redirect("~/Admin/Logout");
}
}
}
@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class FoxTubeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult Screenshots()
{
return View();
}
}
}
@@ -4,38 +4,130 @@ using MyWebsite.Controllers;
using MyWebsite.Models;
using MyWebsite.Models.Databases;
using System.Linq;
using System;
using MyWebsite.ViewModels;
using System.Globalization;
namespace MyWebsite.Areas.Admin.Controllers
{
[Authorize]
[Area("Admin")]
public class GUTScheduleController : ExtendedController
{
const string scheduleOffsetId = "gut.schedule.semester.offset";
const string viewPath = "Areas/Admin/Views/Shared/GUTSchedule.cshtml";
[Authorize]
[Area("Admin")]
public class GUTScheduleController : ExtendedController
{
const string viewPath = "Areas/Admin/Views/Shared/GUTSchedule.cshtml";
public GUTScheduleController(DatabaseContext context) : base(context) { }
private GUTScheduleDatabaseContext db;
[HttpGet]
public IActionResult Index() =>
View(viewPath, Database.CustomData.Find(scheduleOffsetId) ?? new CustomData { Key = scheduleOffsetId, Value = "undefined" });
public GUTScheduleController(DatabaseContext context, GUTScheduleDatabaseContext databaseContext) : base(context) =>
db = databaseContext;
[HttpPost]
public IActionResult Index(CustomData model)
{
if(!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpGet]
public IActionResult Index()
{
ViewData["Policies"] = db.PrivacyPolicies;
return View(viewPath, db.OffsetDates.FirstOrDefault());
}
if(Database.CustomData.Any(i => i.Key == scheduleOffsetId))
Database.CustomData.Update(model);
else
Database.CustomData.Add(model);
Database.SaveChanges();
return View(viewPath, model);
}
}
[HttpPost]
public IActionResult Index(CustomData model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
db.OffsetDates.RemoveRange(db.OffsetDates);
db.OffsetDates.Add(model);
db.SaveChanges();
return Index();
}
[HttpGet]
public IActionResult CreatePolicy()
{
ViewData["Caption"] = "privacy policy";
return View(viewName: "Areas/Admin/Views/Resume/Create.cshtml");
}
[HttpPost]
public IActionResult CreatePolicy(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View("Areas/Admin/Views/Resume/Create.cshtml", model);
}
model.LastUpdate = DateTime.Now;
if (db.PrivacyPolicies.Any(i => i.Language == model.Language))
{
ModelState.AddModelError("Error", $"Resume with this language ({model.Language}) is already exists");
return View("Areas/Admin/Views/Resume/Create.cshtml", model);
}
db.PrivacyPolicies.Add(model);
db.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult DeletePolicy(string id)
{
ViewData["Caption"] = "privacy policy";
return View("Areas/Admin/Views/Resume/Delete.cshtml", db.PrivacyPolicies.Find(id));
}
[HttpPost]
public IActionResult DeletePolicy(ResumeModel model)
{
db.PrivacyPolicies.Remove(model);
db.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult EditPolicy(string id)
{
ViewData["Caption"] = "privacy policy";
return View("Areas/Admin/Views/Resume/Edit.cshtml", db.PrivacyPolicies.Find(id));
}
[HttpPost]
public IActionResult EditPolicy(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View("Areas/Admin/Views/Resume/Edit.cshtml", model);
}
model.LastUpdate = DateTime.Now;
db.PrivacyPolicies.Update(model);
db.SaveChanges();
return RedirectToAction("Index");
}
[AllowAnonymous]
[Route("/Projects/GUTSchedule/PrivacyPolicy")]
public IActionResult PrivacyPolicy() =>
View("Areas/Projects/Views/GUTSchedule/PrivacyPolicy.cshtml", new ResumeViewModel(db.PrivacyPolicies.Find(CultureInfo.CurrentCulture.TwoLetterISOLanguageName) ?? db.PrivacyPolicies.Find("en") ?? db.PrivacyPolicies.Find("ru"), Database));
}
}
@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MyWebsite.Areas.Admin.Models;
using MyWebsite.Controllers;
using MyWebsite.Models;
using MyWebsite.Models.Databases;
@@ -9,90 +9,77 @@ using System.IO;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class GalleryController : ExtendedController
{
public GalleryController(DatabaseContext context) : base(context) { }
[Area("Admin")]
[Authorize]
public class GalleryController : ExtendedController
{
public GalleryController(DatabaseContext context) : base(context) { }
public IActionResult Index() =>
View(Database.Gallery);
public IActionResult Index() =>
View(Database.Gallery);
[HttpGet]
public IActionResult Edit(Guid id)
{
if (Database.Gallery.Find(id) is ImageModel model)
return View(model);
else
return NotFound();
}
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Gallery.Find(id));
[HttpPost]
public IActionResult Edit(ImageModel model)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpPost]
public IActionResult Edit(ImageModel model)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
Database.Gallery.Update(model);
Database.SaveChanges();
Database.Gallery.Update(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Delete(Guid id)
{
if (Database.Gallery.Find(id) is ImageModel model)
return View(model);
else
return NotFound();
}
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Gallery.Find(id));
[HttpPost]
public IActionResult Delete(ImageModel model)
{
Database.Gallery.Remove(model);
Database.SaveChanges();
[HttpPost]
public IActionResult Delete(ImageModel model)
{
Database.Gallery.Remove(model);
Database.SaveChanges();
System.IO.File.SetAttributes(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + model?.FileName, FileAttributes.Normal);
System.IO.File.Delete(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + model?.FileName);
System.IO.File.SetAttributes(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + model?.FileName, FileAttributes.Normal);
System.IO.File.Delete(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + model?.FileName);
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Upload() =>
View();
[HttpGet]
public IActionResult Upload() =>
View(model: null);
[HttpPost]
public IActionResult Upload(ArtworkModel model)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpPost]
public IActionResult Upload(ImageModel model, IFormFile file)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (file == null)
throw new ArgumentNullException(nameof(file));
using (var stream = System.IO.File.Create(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + model?.File.FileName))
model.File.CopyTo(stream);
model.FileName = file.FileName;
ImageModel image = new ImageModel
{
EnglishTitle = model.EnglishTitle,
RussianTitle = model.RussianTitle,
EnglishDescription = model.EnglishDescription,
RussianDescription = model.RussianDescription,
CreationDate = model.CreationDate,
FileName = model.File.FileName
};
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
Database.Gallery.Add(image);
Database.SaveChanges();
using (var stream = System.IO.File.Create(Directory.GetCurrentDirectory() + "/wwwroot/images/Gallery/" + file.FileName))
file.CopyTo(stream);
return RedirectToAction("Index");
}
}
Database.Gallery.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
}
}
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MyWebsite.Controllers;
@@ -7,57 +9,98 @@ using MyWebsite.Models.Databases;
namespace MyWebsite.Areas.Admin.Controllers
{
[Area("Admin")]
[Authorize]
public class ProjectsController : ExtendedController
{
public ProjectsController(DatabaseContext context) : base(context) { }
[Area("Admin")]
[Authorize]
public class ProjectsController : ExtendedController
{
public ProjectsController(DatabaseContext context) : base(context) { }
public IActionResult Index() =>
View((Database.Projects as IEnumerable<ProjectModel>, Database.Badges as IEnumerable<BadgeModel>));
[HttpGet]
public IActionResult Index() =>
View((Database.Projects as IEnumerable<ProjectModel>, Database.Badges as IEnumerable<BadgeModel>));
[HttpGet]
public IActionResult Delete(decimal id) =>
View(Database.Projects.Find(id));
[HttpPost]
public IActionResult Index(Guid[] reorderList)
{
if (reorderList?.Length != Database.Projects.Count())
ModelState.AddModelError("Error", "Invalid or incomplete data recieved");
else
{
for (int i = 0; i < reorderList.Length; i++)
Database.Projects.Find(reorderList[i]).Order = i;
[HttpPost]
public IActionResult Delete(ProjectModel model)
{
Database.Projects.Remove(model);
Database.SaveChanges();
Database.SaveChanges();
}
return RedirectToAction("Index");
}
return View((Database.Projects as IEnumerable<ProjectModel>, Database.Badges as IEnumerable<BadgeModel>));
}
[HttpGet]
public IActionResult Create() =>
View();
[HttpGet]
public IActionResult Delete(Guid id)
{
ViewData["Badges"] = Database.Badges.ToList();
return View(Database.Projects.Find(id));
}
[HttpPost]
public IActionResult Create(ProjectModel model)
{
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
[HttpPost]
public IActionResult Delete(ProjectModel model)
{
Database.Projects.Remove(model);
Database.SaveChanges();
Database.Projects.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
}
[HttpGet]
public IActionResult Edit(Guid id)
{
ViewData["Badges"] = Database.Badges.ToList();
return View(Database.Projects.Find(id));
}
public class ProjectEditorModel
{
public double Id { get; set; }
public string EnglishTitle { get; set; }
public string RussianTitle { get; set; }
public string EnglishDescription { get; set; }
public string RussianDescription { get; set; }
public string Link { get; set; }
public string EnglishLinkCaption { get; set; }
public string RussianLinkCaption { get; set; }
}
[HttpPost]
public IActionResult Edit(ProjectModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
ViewData["Badges"] = Database.Badges.ToList();
return View(model);
}
Database.Projects.Update(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Create()
{
ViewData["Badges"] = Database.Badges.ToList();
return View(model: null);
}
[HttpPost]
public IActionResult Create(ProjectModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
model.Order = Database.Projects.Count();
Database.Projects.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
}
}
@@ -4,77 +4,84 @@ using MyWebsite.Controllers;
using MyWebsite.Models;
using MyWebsite.Models.Databases;
using System;
using System.Linq;
namespace MyWebsite.Areas.Admin.Controllers
{
[Authorize]
[Area("Admin")]
public class ResumeController : ExtendedController
{
public ResumeController(DatabaseContext context) : base(context) { }
[Authorize]
[Area("Admin")]
public class ResumeController : ExtendedController
{
public ResumeController(DatabaseContext context) : base(context) { }
public IActionResult Index() =>
View(Database.Resume);
public IActionResult Index() =>
View(Database.Resume);
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Resume.Find(id));
[HttpGet]
public IActionResult Edit(string id) =>
View(Database.Resume.Find(id));
[HttpPost]
public IActionResult Edit(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
[HttpPost]
public IActionResult Edit(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
model.LastUpdate = DateTime.Now;
model.LastUpdate = DateTime.Now;
Database.Resume.Update(model);
Database.SaveChanges();
Database.Resume.Update(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Resume.Find(id));
[HttpGet]
public IActionResult Delete(string id) =>
View(Database.Resume.Find(id));
[HttpPost]
public IActionResult Delete(ResumeModel model)
{
Database.Resume.Remove(model);
Database.SaveChanges();
[HttpPost]
public IActionResult Delete(ResumeModel model)
{
Database.Resume.Remove(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
[HttpGet]
public IActionResult Create() =>
View();
[HttpGet]
public IActionResult Create() =>
(this as Controller).View();
[HttpPost]
public IActionResult Create(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
[HttpPost]
public IActionResult Create(ResumeModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
if (!ModelState.IsValid)
{
ModelState.AddModelError("Error", "Invalid data");
return View(model);
}
model.LastUpdate = DateTime.Now;
model.LastUpdate = DateTime.Now;
Database.Resume.Add(model);
Database.SaveChanges();
if(Database.Resume.Any(i => i.Language == model.Language))
{
ModelState.AddModelError("Error", $"Resume with this language ({model.Language}) is already exists");
return View(model);
}
return RedirectToAction("Index");
}
}
Database.Resume.Add(model);
Database.SaveChanges();
return RedirectToAction("Index");
}
}
}
@@ -1,29 +0,0 @@
using Microsoft.AspNetCore.Http;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MyWebsite.Areas.Admin.Models
{
public class ArtworkModel
{
[Required]
[DisplayName("Title (en)")]
public string EnglishTitle { get; set; }
[DisplayName("Title (ru)")]
public string RussianTitle { get; set; }
[Required]
[DisplayName("Description (en)")]
public string EnglishDescription { get; set; }
[DisplayName("Description (ru)")]
public string RussianDescription { get; set; }
[Required]
[DisplayName("Created")]
public DateTime CreationDate { get; set; }
[Required]
[DisplayName("File")]
public IFormFile File { get; set; }
}
}
@@ -1,14 +0,0 @@
using MyWebsite.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyWebsite.Areas.Admin.Models
{
public class CredentialModel
{
public MyWebsite.Models.CredentialModel Current { get; set; } = new MyWebsite.Models.CredentialModel();
public MyWebsite.Models.CredentialModel Updated { get; set; } = new MyWebsite.Models.CredentialModel();
}
}
@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyWebsite.Areas.Admin.Models
{
public enum ReorderDirection { Up, Down }
public class ReorderModel
{
public string ItemId { get; set; }
public ReorderDirection Direction { get; set; }
}
}
@@ -1,57 +1,47 @@
@model MyWebsite.Models.BadgeModel
@using System.IO;
@{
ViewData["Title"] = "Create badge";
List<SelectListItem> files = new List<SelectListItem>();
foreach (string path in Directory.GetFiles(Directory.GetCurrentDirectory() + "/wwwroot/images/Badges"))
{
string fileName = System.IO.Path.GetFileNameWithoutExtension(path);
files.Add(new SelectListItem(fileName, fileName));
}
ViewData["Title"] = "Create badge";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Create project badge</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Create project badge</h1>
</header>
<article>
<form asp-action="Create" oninput="UpdatePreview();">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<input asp-for="EnglishDescription" type="text" />
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<input asp-for="RussianDescription" type="text" />
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Image"></label>
<div class="image-selector">
<select asp-for="Image" asp-items="files" onchange="UpdatePreview();"></select>
<span>.png</span>
</div>
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<partial name="Preview.cshtml" />
<form asp-action="Create" oninput="UpdatePreview();">
<div asp-validation-summary="All" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" placeholder="Enter unique badge name" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<input asp-for="EnglishDescription" type="text" required />
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<input asp-for="RussianDescription" type="text" />
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Image"></label>
<div class="image-selector">
<select asp-for="Image" onchange="UpdatePreview();" required>
@foreach (string path in System.IO.Directory.GetFiles(System.IO.Directory.GetCurrentDirectory() + "/wwwroot/images/Badges"))
{
string file = System.IO.Path.GetFileNameWithoutExtension(path);
<option value="@file">@file</option>
}
</select>
<span>.png</span>
</div>
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<partial name="Preview.cshtml" />
<input type="submit" value="Create" class="btn" />
</form>
<hr />
<h2>Upload badge image</h2>
<form method="post" enctype="multipart/form-data">
<input type="file" accept="image/png" name="file" />
<label for="file" style="@(ViewData.Keys.Contains("UploadException") ? "color: red" : "")">File must be a 64x64 PNG image</label>
<input type="submit" value="Upload image" class="btn" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<input type="submit" value="Create" />
</form>
</article>
@@ -1,37 +1,41 @@
@model MyWebsite.Models.BadgeModel
@{
ViewData["Title"] = "Delete badge";
ViewData["Title"] = "Delete badge";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Delete project badge</h1>
<h3>Are you sure you want to delete this?</h3>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Delete project badge</h1>
<h3>Are you sure you want to delete this?</h3>
</header>
<article>
<p>
<b>@Html.DisplayNameFor(model => model.Name):</b> @Model.Name<br />
<b>@Html.DisplayNameFor(model => model.EnglishDescription):</b> @Model.EnglishDescription<br />
<b>@Html.DisplayNameFor(model => model.RussianDescription):</b> @Model.RussianDescription<br />
<b>@Html.DisplayNameFor(model => model.Image):</b> @(Model.Image).png<br />
<div asp-validation-summary="All" class="text-danger"></div>
<p>
<b>@Html.DisplayNameFor(model => model.Name):</b> @Model.Name<br />
<b>@Html.DisplayNameFor(model => model.EnglishDescription):</b> @Model.EnglishDescription<br />
<b>@Html.DisplayNameFor(model => model.RussianDescription):</b> @Model.RussianDescription<br />
<b>@Html.DisplayNameFor(model => model.Image):</b> @(Model.Image).png<br />
<b>Preview:</b>
<div class="badge" style="background-image: url('/images/Badges/@(Model.Image).png')" title="@(Model.Description)"></div>
</p>
<b>Preview:</b>
<div class="badge" style="background-image: url('/images/Badges/@(Model.Image).png')" title="@(Model.Description)"></div>
</p>
<form asp-action="Delete">
<input hidden asp-for="Name" />
<input type="submit" value="Delete" class="btn-danger" />
</form>
<form asp-action="Delete">
<input hidden asp-for="Name" />
<input type="submit" value="Delete" required />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
.badge {
height: 50px;
width: 50px;
background-size: contain;
}
</style>
@section Imports
{
<style type="text/css">
.badge
{
height: 50px;
width: 50px;
background-size: contain;
}
</style>
}
@@ -1,57 +1,47 @@
@using System.IO;
@model MyWebsite.Models.BadgeModel
@model MyWebsite.Models.BadgeModel
@{
ViewData["Title"] = "Edit badge";
List<SelectListItem> files = new List<SelectListItem>();
foreach (string path in Directory.GetFiles(Directory.GetCurrentDirectory() + "/wwwroot/images/Badges"))
{
string fileName = System.IO.Path.GetFileNameWithoutExtension(path);
files.Add(new SelectListItem(fileName, fileName));
}
ViewData["Title"] = "Edit badge";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Edit project badge</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Edit project badge</h1>
</header>
<article>
<form asp-action="Edit" oninput="UpdatePreview();">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" class="readonly" readonly />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<input asp-for="EnglishDescription" type="text" />
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<input asp-for="RussianDescription" type="text" />
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Image"></label>
<div class="image-selector">
<select asp-for="Image" asp-items="files" onchange="UpdatePreview();"></select>
<span>.png</span>
</div>
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<partial name="Preview.cshtml" />
<form asp-action="Edit" oninput="UpdatePreview();">
<div asp-validation-summary="All" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" readonly />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<input asp-for="EnglishDescription" type="text" required />
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<input asp-for="RussianDescription" type="text" />
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Image"></label>
<div class="image-selector">
<select asp-for="Image" onchange="UpdatePreview();" required>
@foreach (string path in System.IO.Directory.GetFiles(System.IO.Directory.GetCurrentDirectory() + "/wwwroot/images/Badges"))
{
string file = System.IO.Path.GetFileNameWithoutExtension(path);
<option value="@file">@file</option>
}
</select>
<span>.png</span>
</div>
<span asp-validation-for="Image" class="text-danger"></span>
</div>
<partial name="Preview.cshtml" />
<input type="submit" value="Save" class="btn" />
</form>
<hr />
<h2>Upload badge image</h2>
<form method="post" enctype="multipart/form-data">
<input type="file" accept="image/png" name="file" />
<label for="file" style="@(ViewData.Keys.Contains("UploadException") ? "color: red" : "")">File must be a 64x64 PNG image</label>
<input type="submit" value="Upload image" class="btn"/>
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<input type="submit" value="Update" />
</form>
</article>
@@ -1,62 +1,159 @@
@model IEnumerable<MyWebsite.Models.BadgeModel>
@{
ViewData["Title"] = "Badges list";
ViewData["Title"] = "Badges list";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Project badges list</h1>
<p>
<a asp-action="Create" class="comment">// + Create New</a>
</p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Project badges list</h1>
<a asp-action="Create" class="comment">// + Create New</a>
</header>
<article>
<table class="table">
<thead>
<tr>
<th>Preview</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.EnglishDescription)
</th>
<th>
@Html.DisplayNameFor(model => model.RussianDescription)
</th>
<th>
@Html.DisplayNameFor(model => model.Image)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
<div class="badge" style="background-image: url(/images/Badges/@(item.Image).png)" title="@(item.Description)"></div>
</td>
<td>@item.Name</td>
<td>@item.EnglishDescription</td>
<td>@item.RussianDescription</td>
<td>@item.Image</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Name">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Name">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<table>
<thead>
<tr>
<th>Preview</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.EnglishDescription)
</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.RussianDescription)
</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.Image)
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
<div class="badge" style="background-image: url(/images/Badges/@(item.Image).png)" title="@(item.Description)"></div>
</td>
<td class="hide-l2">@item.Name</td>
<td>@item.EnglishDescription</td>
<td class="hide-l2">@item.RussianDescription</td>
<td class="hide-l1">@item.Image</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Name">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Name">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
.badge {
height: 25px;
width: 25px;
background-size: contain;
}
</style>
<header>
<hr />
<h1>Badge image files</h1>
</header>
<article>
<h2>Upload new badge image</h2>
<form method="post" enctype="multipart/form-data">
<div asp-validation-summary="All" class="text-danger"></div>
<label for="badgeImage">Badge image file</label>
<input name="badgeImage" type="file" required />
<span>
<b>Note:</b> Image should be exactly 64x64 pixels PNG file
</span>
<br />
<button>Upload</button>
</form>
<h2>Available badge images</h2>
<table class="files-table">
<thead>
<tr>
<th>Preview</th>
<th>File name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (string path in System.IO.Directory.GetFiles(System.IO.Directory.GetCurrentDirectory() + "/wwwroot/images/Badges"))
{
string file = System.IO.Path.GetFileName(path);
<tr>
<td>
<div class="badge" style="background-image: url(/images/Badges/@(file))" title="@(file)"></div>
</td>
<td>@file</td>
<td>
@if (Model.Any(i => i.Image + ".png" == file))
{
<span class="hide-l2" title="Delete or edit correlated badges linked with the image in order to delete it">No available actions</span>
}
else
{
<a asp-action="DeleteBadgeImage" asp-route-id="@file" onclick="return ConfirmDetetion('@file')">Delete</a>
}
</td>
</tr>
}
</tbody>
</table>
</article>
@section Imports
{
<style type="text/css">
.badge
{
height: 25px;
width: 25px;
background-size: contain;
}
.files-table
{
max-width: 500px;
}
td span
{
color: gray;
cursor: help;
}
td span:after
{
content: " (?)";
}
</style>
<script type="text/javascript">
function ConfirmDetetion(filename)
{
return confirm("Are you really want to delete \"" + filename + "\"? This action cannot be undone");
}
function Upload()
{
var form = document.createElement("form");
form.method = "post";
form.hidden = true;
document.body.appendChild(form);
var input = document.createElement("input");
input.type = "file";
input.name = "badgeImage";
input.click();
input.onchange = function ()
{
form.appendChild(input);
form.submit();
}
}
</script>
}
@@ -1,55 +1,52 @@
@model MyWebsite.Models.LinkModel
@{
ViewData["Title"] = "Create link";
ViewData["Title"] = "Create link";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Create link</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Create link</h1>
</header>
<article>
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="Order"></label>
<input asp-for="Order" type="number" />
<span asp-validation-for="Order" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="Username"></label>
<input asp-for="Username" type="text" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div>
<label asp-for="Url"></label>
<input asp-for="Url" type="text" />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
<form asp-action="Create">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Order" type="number" hidden value="-1" />
<div>
<label asp-for="Name"></label>
<a target="_blank" class="comment" href="//socicon.com/icons">// Socicon naming cheatsheet</a>
<input asp-for="Name" type="text" required />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="Username"></label>
<input asp-for="Username" type="text" required />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div>
<label asp-for="Url"></label>
<input asp-for="Url" type="text" required />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
<div>
<input type="checkbox" class="checkbox" asp-for="CanContactMe" />
<label asp-for="CanContactMe"></label> <br />
</div>
<div>
<input type="checkbox" class="checkbox" asp-for="DisplayInFooter" />
<label asp-for="DisplayInFooter"></label>
</div>
<label asp-for="CanContactMe"></label>
<input type="checkbox" class="checkbox" asp-for="CanContactMe" /> <br />
<label asp-for="DisplayInFooter"></label>
<input type="checkbox" class="checkbox" asp-for="DisplayInFooter" />
<input type="submit" value="Create" class="btn" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<input type="submit" value="Create" />
</form>
</article>
@@ -1,31 +1,28 @@
@model MyWebsite.Models.LinkModel
@{
ViewData["Title"] = "Delete link";
ViewData["Title"] = "Delete link";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Delete link</h1>
<h3>Are you sure you want to delete this?</h3>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Delete link</h1>
<h3>Are you sure you want to delete this?</h3>
</header>
<article>
<p class="form-group">
<b>@Html.DisplayNameFor(model => model.Name):</b> @Model.Name<br />
<b>@Html.DisplayNameFor(model => model.Order):</b> @Model.Order<br />
<b>@Html.DisplayNameFor(model => model.EnglishTitle):</b> @Model.EnglishTitle<br />
<b>@Html.DisplayNameFor(model => model.RussianTitle):</b> @Model.RussianTitle<br />
<b>@Html.DisplayNameFor(model => model.Username):</b> @Model.Username<br />
<b>@Html.DisplayNameFor(model => model.Url):</b> @Model.Url<br />
<b>@Html.DisplayNameFor(model => model.CanContactMe):</b> @Html.DisplayFor(model => model.CanContactMe)<br />
<b>@Html.DisplayNameFor(model => model.DisplayInFooter):</b> @Html.DisplayFor(model => model.DisplayInFooter)
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Name):</b> @Model.Name<br />
<b>@Html.DisplayNameFor(model => model.Order):</b> @Model.Order<br />
<b>@Html.DisplayNameFor(model => model.EnglishTitle):</b> @Model.EnglishTitle<br />
<b>@Html.DisplayNameFor(model => model.RussianTitle):</b> @Model.RussianTitle<br />
<b>@Html.DisplayNameFor(model => model.Username):</b> @Model.Username<br />
<b>@Html.DisplayNameFor(model => model.Url):</b> <a href="@Model.Url" target="_blank">@Model.Url</a><br />
<b>@Html.DisplayNameFor(model => model.CanContactMe):</b> @Html.DisplayFor(model => model.CanContactMe)<br />
<b>@Html.DisplayNameFor(model => model.DisplayInFooter):</b> @Html.DisplayFor(model => model.DisplayInFooter)
</p>
<form asp-action="Delete">
<input hidden asp-for="Name" />
<input type="submit" value="Delete" class="btn-danger" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<form asp-action="Delete">
<input hidden asp-for="Name" />
<input type="submit" value="Delete" required />
</form>
</article>
@@ -1,53 +1,50 @@
@model MyWebsite.Models.LinkModel
@{
ViewData["Title"] = "Edit link";
ViewData["Title"] = "Edit link";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Edit link</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Edit link</h1>
</header>
<article>
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" class="readonly" readonly />
</div>
<div>
<label asp-for="Order"></label>
<input asp-for="Order" type="number" />
<span asp-validation-for="Order" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="Username"></label>
<input asp-for="Username" type="text" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div>
<label asp-for="Url"></label>
<input asp-for="Url" type="text" />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
<form asp-action="Edit">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Order" type="number" hidden />
<div>
<label asp-for="Name"></label>
<input asp-for="Name" type="text" readonly />
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="Username"></label>
<input asp-for="Username" type="text" required />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div>
<label asp-for="Url"></label>
<input asp-for="Url" type="text" required />
<span asp-validation-for="Url" class="text-danger"></span>
</div>
<div>
<input type="checkbox" class="checkbox" asp-for="CanContactMe" />
<label asp-for="CanContactMe"></label> <br />
</div>
<div>
<input type="checkbox" class="checkbox" asp-for="DisplayInFooter" />
<label asp-for="DisplayInFooter"></label>
</div>
<label asp-for="CanContactMe"></label>
<input type="checkbox" class="checkbox" asp-for="CanContactMe" /> <br />
<label asp-for="DisplayInFooter"></label>
<input type="checkbox" class="checkbox" asp-for="DisplayInFooter" />
<input type="submit" value="Save" class="btn" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<input type="submit" value="Save" />
</form>
</article>
@@ -1,75 +1,90 @@
@model IEnumerable<MyWebsite.Models.LinkModel>
@{
ViewData["Title"] = "Links list";
ViewData["Title"] = "Links list";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Links list</h1>
<p>
<a asp-action="Create" class="comment">// + Create New</a>
</p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Links list</h1>
<a asp-action="Create" class="comment">// + Create New</a>
</header>
<article>
<table>
<thead>
<tr>
<th>Reorder</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.EnglishTitle)
</th>
<th>
@Html.DisplayNameFor(model => model.RussianTitle)
</th>
<th>
@Html.DisplayNameFor(model => model.Username)
</th>
<th>
@Html.DisplayNameFor(model => model.Url)
</th>
<th>
@Html.DisplayNameFor(model => model.CanContactMe)
</th>
<th>
@Html.DisplayNameFor(model => model.DisplayInFooter)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.OrderBy(i => i.Order))
{
<tr draggable="true" ondragover="onDragOver(event);">
<td>&#xE700;</td>
<td>@item.Name</td>
<td>@item.EnglishTitle</td>
<td>@item.RussianTitle</td>
<td>@item.Username</td>
<td>@item.Url</td>
<td>
@Html.DisplayFor(modelItem => item.CanContactMe)
</td>
<td>
@Html.DisplayFor(modelItem => item.DisplayInFooter)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Name">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Name">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<div asp-validation-summary="All" class="text-danger"></div>
<table>
<thead>
<tr>
<th>&#xE700;</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.Title)
</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.Username)
</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.Url)
</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.CanContactMe)
</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.DisplayInFooter)
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.OrderBy(i => i.Order))
{
<tr id="@item.Name">
<td class="reorderingBtns">
<a onclick="Up(this)">&#xE010;</a><br />
<span>&#xE915;</span><br />
<a onclick="Down(this)">&#xE011;</a>
</td>
<td>@item.Name</td>
<td class="hide-l2">
@item.EnglishTitle (en)<br />
@(item.RussianTitle ?? "<not_set>") (ru)
</td>
<td class="hide-l1">@item.Username</td>
<td class="hide-l2"><a target="_blank" href="@item.Url">@item.Url</a></td>
<td class="hide-l1">
@Html.DisplayFor(modelItem => item.CanContactMe)
</td>
<td class="hide-l1">
@Html.DisplayFor(modelItem => item.DisplayInFooter)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Name">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Name">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<button onclick="ApplyReorder()" disabled>Apply reordering</button>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<script type="text/javascript">
function onDragOver(event)
{
this.style.marginTop = '20px';
}
</script>
@section Imports
{
<style type="text/css">
.reorderingBtns
{
user-select: none;
}
.reorderingBtns a:hover
{
cursor: pointer;
color: gray;
text-decoration: underline;
}
</style>
<script type="text/javascript" src="~/js/ReorderScript.js"></script>
}
@@ -0,0 +1,18 @@
@{
ViewData["Title"] = "FoxTube";
}
<header>
<h1>FoxTube Backend control panel</h1>
</header>
<article class="admin-menu">
<p>
<a asp-action="Gallery" class="comment">// Messages and changelogs</a><br />
<a asp-action="Gallery" class="comment">// Recieved metrics</a>
</p>
<p>
<a asp-action="Gallery" class="comment">// Privacy policies</a><br />
<a asp-action="Gallery" class="comment">// Screenshots</a>
</p>
</article>
@@ -1,34 +1,61 @@
@model MyWebsite.Models.ImageModel
@{
ViewData["Title"] = "Delete artwork";
ViewData["Title"] = "Delete artwork";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Delete artwork</h1>
<h3>Are you sure you want to delete this?</h3>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Delete artwork</h1>
<h3>Are you sure you want to delete this?</h3>
</header>
<article class="image-overview-block">
<img src="~/images/Gallery/@Model.FileName" onclick="ToggleImageSize();" id="image" />
<img src="~/images/Gallery/@Model.FileName" onclick="ToggleImageSize();" />
<div>
<p>
<b>@Html.DisplayNameFor(model => model.Title):</b> @Model.Title<br />
<b>@Html.DisplayNameFor(model => model.CreationDate):</b> @Model.CreationDate<br />
<b>@Html.DisplayNameFor(model => model.FileName):</b> @Model.FileName<br />
</p>
<div>
<p>
<b>@Html.DisplayNameFor(model => model.Title):</b> @Model.Title<br />
<b>@Html.DisplayNameFor(model => model.CreationDate):</b> @Model.CreationDate<br />
<b>@Html.DisplayNameFor(model => model.FileName):</b> @Model.FileName<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Description):</b> @Html.Raw(Model.Description)<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Description):</b> @Html.Raw(Model.Description)<br />
</p>
<form asp-action="Delete">
<input hidden asp-for="FileName" />
<input type="submit" value="Delete" class="btn-danger" />
</form>
</div>
<form asp-action="Delete">
<input hidden asp-for="FileName" />
<input type="submit" value="Delete" required />
</form>
</div>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<link type="text/css" rel="stylesheet" href="~/css/Gallery.css" />
@section Imports
{
<link type="text/css" rel="stylesheet" href="~/css/Gallery.css" />
<style type="text/css">
@@media only screen and (max-width: 500px)
{
.image-overview-block > div
{
margin: initial;
}
}
</style>
<script type="text/javascript">
function ToggleImageSize()
{
var image = document.querySelector("img");
if (image.style.cursor == "zoom-out")
image.style = "";
else
{
image.style.maxHeight = "none";
image.style.maxWidth = "none";
image.style.cursor = "zoom-out";
}
}
</script>
}
@@ -1,48 +1,97 @@
@model MyWebsite.Models.ImageModel
@{
ViewData["Title"] = "Edit artwork";
ViewData["Title"] = "Edit artwork";
}
<header>
<p>
&#xE760; <a asp-action="Index">Back to the list</a> <br />
<h1>Edit artwork</h1>
<a class="comment" href="~/images/Gallery/@(Model.FileName)" target="_blank">// Open artwork</a>
</p>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Edit artwork</h1>
<a class="comment" href="~/images/Gallery/@(Model.FileName)" target="_blank">// Open artwork file</a>
</header>
<article>
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="FileName" hidden/>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription"></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="CreationDate"></label>
<input asp-for="CreationDate" type="date" />
<span asp-validation-for="CreationDate" class="text-danger"></span>
</div>
<img src="~/images/Gallery/@Model.FileName" onclick="ToggleImageSize();" />
<input type="submit" value="Save" class="btn" />
</form>
<form asp-action="Edit">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="FileName" hidden />
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required/>
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription"></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="CreationDate"></label>
<input asp-for="CreationDate" type="date" required/>
<span asp-validation-for="CreationDate" class="text-danger"></span>
</div>
<input type="submit" value="Save" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
@section Imports
{
<script type="text/javascript">
function ToggleImageSize()
{
var image = document.querySelector("img");
if (image.style.cursor == "zoom-out")
image.style = "";
else
{
image.style.maxHeight = "none";
image.style.maxWidth = "none";
image.style.cursor = "zoom-out";
}
}
</script>
<style type="text/css">
article
{
display: grid;
grid-template-columns: 500px 1fr;
grid-column-gap: 20px;
}
article img
{
width: 100%;
}
@@media only screen and (max-width: 1000px)
{
article
{
display: inherit;
}
}
form
{
max-width: initial;
}
textarea
{
max-height: 250px;
}
</style>
}
@@ -1,47 +1,53 @@
@model IEnumerable<MyWebsite.Models.ImageModel>
@{
ViewData["Title"] = "Gallery";
ViewData["Title"] = "Gallery";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Gallery</h1>
<p>
<a asp-action="Upload" class="comment">// + Upload new</a>
</p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Gallery</h1>
<a asp-action="Upload" class="comment">// &#xE11C; Upload new</a>
</header>
<article>
<table>
@foreach (ImageModel item in Model)
{
<tr>
<td>
<img title="@item.Title" src="~/images/Gallery/@item.FileName" />
</td>
<td>
<p>
<h3>@item.Title</h3>
<span>File name: @item.FileName</span><br />
<span>Creation date: @item.CreationDate.ToShortDateString()</span><br />
<span>
@Html.ActionLink("Edit", "Edit", new { id = item.FileName }) |
@Html.ActionLink("Delete", "Delete", new { id = item.FileName })
</span>
</p>
</td>
</tr>
}
</table>
<table>
@foreach (ImageModel item in Model)
{
<tr>
<td>
<a asp-area="" asp-controller="Gallery" asp-action="Details" asp-route-id="@item.FileName" target="_blank">
<img title="@item.Title" src="~/images/Gallery/@item.FileName" />
</a>
</td>
<td>
<p>
<h3>@item.Title</h3>
<span>File name: @item.FileName</span><br />
<span>Creation date: @item.CreationDate.ToShortDateString()</span><br />
<span>
<a asp-action="Edit" asp-route-id="@item.FileName">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.FileName">Delete</a> |
<a asp-area="" asp-controller="Gallery" asp-action="Details" asp-route-id="@item.FileName" target="_blank">View</a>
</span>
</p>
</td>
</tr>
}
</table>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
img {
height: 200px;
margin-right: 20px;
}
table {
width: initial;
}
</style>
@section Imports
{
<style type="text/css">
img
{
height: 200px;
margin-right: 20px;
}
table
{
width: initial;
}
</style>
}
@@ -1,49 +1,61 @@
@model ArtworkModel
@model ImageModel
@{
ViewData["Title"] = "Upload artwork";
ViewData["Title"] = "Upload artwork";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Upload an artwork</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Upload an artwork</h1>
</header>
<article>
<form asp-action="Upload">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription"></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="CreationDate"></label>
<input asp-for="CreationDate" type="date" />
<span asp-validation-for="CreationDate" class="text-danger"></span>
</div>
<div>
<label asp-for="File"></label>
<input type="file" accept="image" asp-for="File" />
<span asp-validation-for="File" class="text-danger"></span>
</div>
<form asp-action="Upload" enctype="multipart/form-data">
<div>
<label for="file">Artwork file</label>
<input type="file" accept="image" name="File" required />
</div>
<div asp-validation-summary="All" class="text-danger"></div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription"></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="CreationDate"></label>
<input asp-for="CreationDate" type="date" required />
<span asp-validation-for="CreationDate" class="text-danger"></span>
</div>
<input type="submit" value="Upload" class="btn" />
</form>
<input type="submit" value="Upload" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
@section Imports
{
<style type="text/css">
form
{
max-width: initial;
}
textarea
{
max-height: 250px;
}
</style>
}
@@ -1,64 +1,107 @@
@model MyWebsite.Models.ProjectModel
@{
ViewData["Title"] = "New Project";
ViewData["Title"] = "New Project";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Create new project</h1>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Create new project</h1>
</header>
<article>
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Id"></label>
<input asp-for="Id" type="number"/>
<span asp-validation-for="Id" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text"/>
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text"/>
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription"></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Link"></label>
<input asp-for="Link" type="url"/>
<span asp-validation-for="Link" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishLinkCaption"></label>
<input asp-for="EnglishLinkCaption" type="text"/>
<span asp-validation-for="EnglishLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianLinkCaption"></label>
<input asp-for="RussianLinkCaption" type="text"/>
<span asp-validation-for="RussianLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="Badges"></label>
<input asp-for="Badges" type="text" />
<span asp-validation-for="Badges" class="text-danger"></span>
</div>
<form asp-action="Create" onsubmit="ConfigureBadges()">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Order" type="number" value="-1" hidden />
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription" required></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Link"></label>
<input asp-for="Link" type="text" />
<span asp-validation-for="Link" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishLinkCaption"></label>
<input asp-for="EnglishLinkCaption" type="text" />
<span asp-validation-for="EnglishLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianLinkCaption"></label>
<input asp-for="RussianLinkCaption" type="text" />
<span asp-validation-for="RussianLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="Badges"></label>
<input asp-for="Badges" type="text" id="badges" hidden />
<span asp-validation-for="Badges" class="text-danger"></span>
<div class="badge-list">
@foreach (BadgeModel badge in ViewData["Badges"] as List<BadgeModel>)
{
<input type="checkbox" id="@badge.Name"/>
<div class="badge" style="background-image: url('/images/Badges/@(badge?.Image).png')" title="@(badge?.Description)"></div>
<span>@badge.Description</span><br />
}
</div>
</div>
<input type="submit" value="Create" class="btn" />
</form>
<input type="submit" value="Create" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
@section Imports
{
<script type="text/javascript">
function ConfigureBadges()
{
var checkboxes = document.querySelectorAll(".badge-list input");
var badges = [];
for (var k = 0; k < checkboxes.length; k++)
if (checkboxes[k].checked == true)
badges[badges.length] = checkboxes[k].id;
document.querySelector("#badges").value = badges.join(",");
}
</script>
<style type="text/css">
form
{
max-width: initial;
}
textarea
{
max-height: 250px;
}
.badge-list
{
margin: 10px 0px;
}
.badge-list div
{
height: 25px;
width: 25px;
display: inline-block;
background-size: contain;
}
</style>
}
@@ -1,31 +1,63 @@
@model MyWebsite.Models.ProjectModel
@{
ViewData["Title"] = "Delete project";
ViewData["Title"] = "Delete project";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Delete project entry</h1>
<h3>Are you sure you want to delete this?</h3>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Delete project entry</h1>
<h3>Are you sure you want to delete this?</h3>
</header>
<article>
<p class="form-group">
<b>@Html.DisplayNameFor(model => model.Id):</b> @Model.Id<br />
<b>@Html.DisplayNameFor(model => model.EnglishTitle):</b> @Model.EnglishTitle<br />
<b>@Html.DisplayNameFor(model => model.RussianTitle):</b> @Model.RussianTitle<br />
<b>@Html.DisplayNameFor(model => model.EnglishDescription):</b> @Model.EnglishDescription<br />
<b>@Html.DisplayNameFor(model => model.RussianDescription):</b> @Model.RussianDescription<br />
<b>@Html.DisplayNameFor(model => model.Link):</b> @Model.Link<br />
<b>@Html.DisplayNameFor(model => model.EnglishLinkCaption):</b> @Model.EnglishLinkCaption<br />
<b>@Html.DisplayNameFor(model => model.RussianLinkCaption):</b> @Model.RussianLinkCaption<br />
<b>@Html.DisplayNameFor(model => model.Badges):</b> @Model.Badges<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Id):</b> @Model.Id<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.EnglishTitle):</b> @Model.EnglishTitle<br />
<b>@Html.DisplayNameFor(model => model.RussianTitle):</b> @Model.RussianTitle<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.EnglishLinkCaption):</b> @Model.EnglishLinkCaption<br />
<b>@Html.DisplayNameFor(model => model.RussianLinkCaption):</b> @Model.RussianLinkCaption<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Link):</b> <a target="_blank" href="@Model.Link">@Model.Link</a><br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Badges):</b> @Model.Badges<br />
<div class="badge-placeholder">
@foreach (string b in Model.Badges.Split(','))
{
BadgeModel badge = (ViewData["Badges"] as List<BadgeModel>).FirstOrDefault(i => i.Name == b);
<div style="background-image: url('/images/Badges/@(badge?.Image).png')" title="@(badge?.Description)"></div>
}
</div>
</p>
<form asp-action="Delete">
<input hidden asp-for="Id" />
<input type="submit" value="Delete" class="btn-danger" />
</form>
<form asp-action="Delete">
<input hidden asp-for="Id" />
<input type="submit" value="Delete" required />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
@section Imports
{
<style type="text/css">
.badge-placeholder
{
display: grid;
grid-column-gap: 10px;
grid-auto-columns: max-content;
grid-auto-flow: column;
}
.badge-placeholder div
{
height: 25px;
width: 25px;
display: inline-block;
background-size: contain;
}
</style>
}
@@ -0,0 +1,111 @@
@model MyWebsite.Models.ProjectModel
@{
ViewData["Title"] = "Edit";
}
<header>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Edit project</h1>
</header>
<article>
<form asp-action="Edit" onsubmit="ConfigureBadges()">
<div asp-validation-summary="All" class="text-danger"></div>
<input asp-for="Order" type="number" hidden />
<div>
<label asp-for="Id"></label>
<input asp-for="Id" type="text" readonly />
</div>
<div>
<label asp-for="EnglishTitle"></label>
<input asp-for="EnglishTitle" type="text" required />
<span asp-validation-for="EnglishTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianTitle"></label>
<input asp-for="RussianTitle" type="text" />
<span asp-validation-for="RussianTitle" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishDescription"></label>
<textarea asp-for="EnglishDescription" required></textarea>
<span asp-validation-for="EnglishDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianDescription"></label>
<textarea asp-for="RussianDescription"></textarea>
<span asp-validation-for="RussianDescription" class="text-danger"></span>
</div>
<div>
<label asp-for="Link"></label>
<input asp-for="Link" type="text" />
<span asp-validation-for="Link" class="text-danger"></span>
</div>
<div>
<label asp-for="EnglishLinkCaption"></label>
<input asp-for="EnglishLinkCaption" type="text" />
<span asp-validation-for="EnglishLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="RussianLinkCaption"></label>
<input asp-for="RussianLinkCaption" type="text" />
<span asp-validation-for="RussianLinkCaption" class="text-danger"></span>
</div>
<div>
<label asp-for="Badges"></label>
<input asp-for="Badges" type="text" id="badges" hidden />
<span asp-validation-for="Badges" class="text-danger"></span>
<div class="badge-list">
@foreach (BadgeModel badge in ViewData["Badges"] as List<BadgeModel>)
{
<input type="checkbox" id="@badge.Name" checked="@(Model.Badges.Split(',').Contains(badge.Name))"/>
<div class="badge" style="background-image: url('/images/Badges/@(badge?.Image).png')" title="@(badge?.Description)"></div>
<span>@badge.Description</span><br />
}
</div>
</div>
<input type="submit" value="Save" />
</form>
</article>
@section Imports
{
<script type="text/javascript">
function ConfigureBadges()
{
var checkboxes = document.querySelectorAll(".badge-list input");
var badges = [];
for (var k = 0; k < checkboxes.length; k++)
if (checkboxes[k].checked == true)
badges[badges.length] = checkboxes[k].id;
document.querySelector("#badges").value = badges.join(",");
}
</script>
<style type="text/css">
form
{
max-width: initial;
}
textarea
{
max-height: 250px;
}
.badge-list
{
margin: 10px 0px;
}
.badge-list div
{
height: 25px;
width: 25px;
display: inline-block;
background-size: contain;
}
</style>
}
@@ -1,79 +1,110 @@
@model (IEnumerable<MyWebsite.Models.ProjectModel> projects, IEnumerable<MyWebsite.Models.BadgeModel> badges)
@{
ViewData["Title"] = "Projects";
ViewData["Title"] = "Projects";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Projects list</h1>
<p>
<a asp-action="Create" class="comment">// + Add New</a>
</p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Projects list</h1>
<a asp-action="Create" class="comment">// + Add new project</a>
</header>
<article>
<table>
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.projects.First().Id)
</th>
<th>
@Html.DisplayNameFor(model => model.projects.First().EnglishTitle)
</th>
<th>
@Html.DisplayNameFor(model => model.projects.First().RussianTitle)
</th>
<th>
@Html.DisplayNameFor(model => model.projects.First().Link)
</th>
<th>
@Html.DisplayNameFor(model => model.projects.First().Badges)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.projects.OrderByDescending(i => i.Id))
{
<tr>
<td>@item.Id</td>
<td>@item.EnglishTitle</td>
<td>@item.RussianTitle</td>
<td>@item.Link</td>
<td>
<div class="badge-placeholder">
@foreach (string badge in item.Badges.Split(','))
{
<div style="background-image: @("../images/Badges/" + Model.badges.FirstOrDefault(i => i.Name == badge)?.Image + ".png")" title="@(Model.badges.FirstOrDefault(i => i.Name == badge)?.Description)"></div>
}
</div>
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<div asp-validation-summary="All" class="text-danger"></div>
<table>
<thead>
<tr>
<th>&#xE700;</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.projects.First().Id)
</th>
<th>
@Html.DisplayNameFor(model => model.projects.First().Title)
</th>
<th class="hide-l1">
@Html.DisplayNameFor(model => model.projects.First().LinkCaption)
</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.projects.First().Link)
</th>
<th class="hide-l2">
@Html.DisplayNameFor(model => model.projects.First().Badges)
(<a asp-controller="Badges" asp-action="Index">Edit badges</a>)
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.projects.OrderBy(i => i.Order))
{
<tr id="@item.Id">
<td class="reorderingBtns">
<a onclick="Up(this)">&#xE010;</a><br />
<span>&#xE915;</span><br />
<a onclick="Down(this)">&#xE011;</a>
</td>
<td class="hide-l1">@item.Id</td>
<td>
@item.EnglishTitle (en)<br />
@(item.RussianTitle ?? "<not_set>") (ru)
</td>
<td class="hide-l1">
@(item.EnglishLinkCaption ?? "<not_set>") (en)<br />
@(item.RussianLinkCaption ?? "<not_set>") (ru)
</td>
<td class="hide-l2"><a target="_blank" href="@item.Link">@item.Link</a></td>
<td class="hide-l2">
<div class="badge-placeholder">
@foreach (string b in item.Badges.Split(','))
{
BadgeModel badge = Model.badges.FirstOrDefault(i => i.Name == b);
<div style="background-image: url('../images/Badges/@(badge?.Image).png')" title="@(badge?.Description)"></div>
}
</div>
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<button onclick="ApplyReorder()" disabled>Apply reordering</button>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
.badge-placeholder
{
display: grid;
grid-column-gap: 10px;
grid-auto-columns: max-content;
grid-auto-flow: column;
}
@section Imports
{
<style type="text/css">
.badge-placeholder
{
display: grid;
grid-column-gap: 10px;
grid-auto-columns: max-content;
grid-auto-flow: column;
}
.badge-placeholder div
{
height: 25px;
width: 25px;
display: inline-block;
background-size: contain;
}
</style>
.badge-placeholder div
{
height: 25px;
width: 25px;
display: inline-block;
background-size: contain;
}
.reorderingBtns
{
user-select: none;
}
.reorderingBtns a:hover
{
cursor: pointer;
color: gray;
text-decoration: underline;
}
</style>
<script type="text/javascript" src="~/js/ReorderScript.js"></script>
}
@@ -1,39 +1,48 @@
@using System.Globalization
@model MyWebsite.Models.ResumeModel
@{
ViewData["Title"] = "Create resume";
ViewData["Title"] = "Create " + (ViewData["Caption"] ?? "resume");
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Create resume</h1>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Create @(ViewData["Caption"] ?? "resume")</h1>
</header>
<article>
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div>
<label asp-for="Language"></label>
<input type="text" asp-for="Language"/>
<span asp-validation-for="Language" class="text-danger"></span>
</div>
<div>
<label asp-for="Content"></label>
<textarea asp-for="Content" spellcheck="false"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<br />
<input type="submit" value="Save" class="btn"/>
</form>
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div>
<label asp-for="Language"></label>
<select asp-for="Language" required>
@foreach (var culture in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
{
<option value="@culture.Name">@culture.EnglishName</option>
}
</select>
<span asp-validation-for="Language" class="text-danger"></span>
</div>
<div>
<label asp-for="Content"></label>
<textarea asp-for="Content" spellcheck="false" required></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<br />
<input type="submit" value="Save" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
form {
max-width: initial;
}
@section Imports
{
<style type="text/css">
form
{
max-width: initial;
}
textarea {
min-height: 500px;
}
</style>
textarea
{
min-height: 500px;
}
</style>
}
@@ -1,24 +1,22 @@
@model MyWebsite.Models.ResumeModel
@{
ViewData["Title"] = "Delete resume";
ViewData["Title"] = "Delete " + (ViewData["Caption"] ?? "resume");
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Delete resume</h1>
<h3>Are you sure you want to delete this?</h3>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Delete @(ViewData["Caption"] ?? "resume")</h1>
<h3>Are you sure you want to delete this?</h3>
</header>
<article>
<p class="form-group">
<b>@Html.DisplayNameFor(model => model.Language):</b> @(new System.Globalization.CultureInfo(Model.Language).DisplayName)<br />
<b>@Html.DisplayNameFor(model => model.LastUpdate):</b> @Model.LastUpdate<br />
</p>
<p>
<b>@Html.DisplayNameFor(model => model.Language):</b> @(new System.Globalization.CultureInfo(Model.Language).DisplayName)<br />
<b>@Html.DisplayNameFor(model => model.LastUpdate):</b> @Model.LastUpdate<br />
</p>
<form asp-action="Delete">
<input hidden asp-for="Language" />
<input type="submit" value="Delete" class="btn-danger" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<form method="post">
<input hidden asp-for="Language" />
<input type="submit" value="Delete" required />
</form>
</article>
@@ -1,50 +1,56 @@
@model MyWebsite.Models.ResumeModel
@{
ViewData["Title"] = "Edit resume";
ViewData["Title"] = "Edit " + (ViewData["Caption"] ?? "resume");
}
<header>
<p>&#xE760; <a asp-action="Index">Back to the list</a></p>
<h1>Edit resume</h1>
<p>
Language: @(new System.Globalization.CultureInfo(Model.Language).DisplayName)<br />
Previously updated on @Model.LastUpdate
</p>
&#xE760; <a asp-action="Index">Back to the list</a>
<h1>Edit @(ViewData["Caption"] ?? "resume")</h1>
Language: @(new System.Globalization.CultureInfo(Model.Language).DisplayName)<br />
Previously updated on @Model.LastUpdate<br />
<a class="comment" onclick="CopyToClipboard()">// &#xE16D; Copy to clipboard</a>
</header>
<article>
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="text" asp-for="Language" hidden />
<div>
<textarea asp-for="Content" spellcheck="false"></textarea>
<a class="comment" onclick="CopyToClipboard()" href="#">// &#xE16D; Copy to clipboard</a>
<span style="display: none" id="copied"> - Done</span><br />
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<br />
<input type="submit" value="Save" class=" btn" />
</form>
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<input type="text" asp-for="Language" hidden />
<textarea asp-for="Content" spellcheck="false" required></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
<br />
<input type="submit" value="Save" />
</form>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<style type="text/css">
form {
max-width: initial;
}
textarea {
min-height: 500px;
}
</style>
<script type="text/javascript">
async function CopyToClipboard() {
text = document.getElementById("Content");
text.select();
document.execCommand("copy");
window.getSelection().removeAllRanges();
document.getElementById("copied").style.display = "initial";
await new Promise(res => setTimeout(res, 3000));
document.getElementById("copied").style.display = "none";
}
</script>
@section Imports
{
<style type="text/css">
form
{
max-width: initial;
}
header .comment
{
cursor: pointer;
}
textarea
{
min-height: 500px;
}
</style>
<script type="text/javascript">
function CopyToClipboard()
{
document.querySelector("textarea").select();
document.execCommand("copy");
document.getSelection().removeAllRanges();
alert("CV content copied");
}
</script>
}
@@ -1,44 +1,39 @@
@model IEnumerable<MyWebsite.Models.ResumeModel>
@{
ViewData["Title"] = "Resumes";
ViewData["Title"] = "Resumes";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Resumes list</h1>
<p>
<a asp-action="Create" class="comment">// + Create New</a>
</p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Resumes list</h1>
<a asp-action="Create" class="comment">// + Create New</a>
</header>
<article>
<table>
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Language)
</th>
<th>
@Html.DisplayNameFor(model => model.LastUpdate)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Language</td>
<td>@item.LastUpdate</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Language">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Language">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</article>
<link type="text/css" rel="stylesheet" href="~/css/Admin.css" />
<table>
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Language)
</th>
<th>
@Html.DisplayNameFor(model => model.LastUpdate)
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Language</td>
<td>@item.LastUpdate</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Language">Edit</a> |
<a asp-action="Delete" asp-route-id="@item.Language">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</article>
@@ -1,69 +1,78 @@
@model MyWebsite.Areas.Admin.Models.CredentialModel
@{
ViewData["Title"] = "Edit credential";
@{
ViewData["Title"] = "Edit credential";
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
<h1>Change credential information</h1>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>Change credential information</h1>
</header>
<article>
<form asp-action="Index" onsubmit="return Validate();">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<p>
<label asp-for="Updated.Email">New e-mail:</label>
<input asp-for="Updated.Email" id="new-email" type="email" />
<span asp-validation-for="Updated.Email" class="text-danger" id="email-validation"></span><br />
<label>Confirm e-mail:</label>
<input id="confirm-email" type="email" />
</p>
<p>
<label asp-for="Updated.Password">New password:</label>
<input asp-for="Updated.Password" id="new-password" type="password" />
<span asp-validation-for="Updated.Password" class="text-danger" id="password-validation"></span><br />
<label>Confirm password:</label>
<input id="confirm-password" type="password" />
</p>
<p>
<label asp-for="Current.Email">Current e-mail:</label>
<input asp-for="Current.Email" type="email" />
<span asp-validation-for="Current.Email" class="text-danger"></span><br />
<label asp-for="Current.Password">Current password:</label>
<input asp-for="Current.Password" type="password" />
<span asp-validation-for="Current.Password" class="text-danger"></span>
</p>
<input type="submit" value="Update" />
</form>
<h2>Change e-mail</h2>
<div asp-validation-summary="All" class="text-danger"></div>
<form method="post" onsubmit="return ValidateEmail()">
<label for="value">New e-mail:</label>
<input name="value" id="newEmail" type="email" placeholder="user@example.com" required />
<label>Confirm e-mail:</label>
<input id="confirmEmail" type="email" placeholder="user@example.com" required />
<span class="text-danger" id="emailValidationError"></span>
<input name="key" value="email" hidden />
<button>Update e-mail</button>
</form>
<h2>Change password</h2>
<form method="post" onsubmit="return ValidatePassword()">
<label for="value">New password:</label>
<input name="value" id="newPassword" type="password" required />
<label>Confirm password:</label>
<input id="confirmPassword" type="password" required />
<span class="text-danger" id="passwordValidationError"></span>
<input name="key" value="password" hidden />
<button>Update password</button>
</form>
</article>
<link href="~/css/Admin.css" type="text/css" rel="stylesheet" />
<script type="text/javascript">
var newEmail = document.getElementById("new-email");
var confirmEmail = document.getElementById("confirm-email");
var newPassword = document.getElementById("new-password");
var confirmPassword = document.getElementById("confirm-password");
var emailValidation = document.getElementById("email-validation");
var passwordValidation = document.getElementById("password-validation");
function Validate()
{
var invalid = false;
emailValidation.innerHTML = "";
passwordValidation.innerHTML = "";
if (newEmail.value != "" && newEmail.value != confirmEmail.value)
@section Imports
{
<script type="text/javascript">
function ValidateEmail()
{
emailValidation.innerHTML = "Addresses don't match";
invalid = true;
}
if (newPassword.value != "" && newPassword.value != confirmPassword.value)
{
passwordValidation.innerHTML = "Passwords don't match";
invalid = true;
var newEmail = document.querySelector("#newEmail");
var confirmEmail = document.querySelector("#confirmEmail");
var emailValidation = document.querySelector("#emailValidationError");
emailValidation.innerHTML = "";
if (newEmail.value == confirmEmail.value)
return true;
emailValidation.innerHTML = "E-mail addresses are invalid or doesn't match";
return false;
}
return !invalid;
}
</script>
function ValidatePassword()
{
var newPassword = document.querySelector("#newPassword");
var confirmPassword = document.querySelector("#confirmPassword");
var passwordValidation = document.querySelector("#passwordValidationError");
passwordValidation.innerHTML = "";
if (newPassword.value == confirmPassword.value)
return true;
passwordValidation.innerHTML = "Passwords doesn't match";
return false;
}
</script>
}
@@ -1,22 +1,49 @@
@model CustomData
@{
ViewData["Title"] = "GUTSchedule";
IEnumerable<ResumeModel> policies = ViewData["Policies"] as IEnumerable<ResumeModel>;
}
<header>
<p>&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a></p>
&#xE760; <a asp-action="Index" asp-controller="Admin" asp-area="">Back to main menu</a>
<h1>GUTSchedule</h1>
</header>
<article>
<div asp-validation-summary="All" class="text-danger"></div>
<h2>Offset dates</h2>
<form asp-action="Index">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="Key" hidden />
<label asp-for="Value">First work day in the semester: (Current: @Model.Value)</label>
<input asp-for="Key" value="offset" hidden />
<label asp-for="Value">First work day in the semester: (Current: @Model?.Value)</label>
<input type="number" asp-for="Value" />
<span asp-validation-for="Value" class="text-danger"></span>
<input type="submit" value="Update" class="btn"/>
<input type="submit" value="Update" />
</form>
</article>
<link href="~/css/Admin.css" type="text/css" rel="stylesheet" />
<h2>Privacy policies</h2>
<a class="comment" asp-action="PrivacyPolicy" target="_blank">// View privacy policy page</a><br />
<a class="comment" asp-action="CreatePolicy">// + Add new privacy policy</a>
<table>
<thead>
<tr>
<th>Langauge</th>
<th>Last update</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (ResumeModel item in policies)
{
<tr>
<td>@item.Language</td>
<td>@item.LastUpdate</td>
<td>
<a asp-action="EditPolicy" asp-route-id="@item.Language">Edit</a> |
<a asp-action="DeletePolicy" asp-route-id="@item.Language">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</article>
@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html>
<head>
<title>@ViewData["Title"] - Admin pangel - XFox111.NET</title>
<link rel="shortcut icon" href="~/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="~/css/Style.css" />
<link rel="stylesheet" type="text/css" href="~/css/Fonts.css" />
<link rel="stylesheet" href="https://s3.amazonaws.com/icomoon.io/114779/Socicon/style.css?u8vidh" />
<link href="~/css/Admin.css" type="text/css" rel="stylesheet" />
<script type="text/javascript">
function ToggleMenu()
{
var menu = document.getElementById("main-menu");
if (menu.style.display == "none")
menu.style.display = "initial";
else
menu.style.display = "none";
}
</script>
@RenderSection("Imports", false)
@{
if (IsSectionDefined("OpenGraph"))
RenderSection("OpenGraph");
else
{
<meta name="author" content="Michael 'XFox' Gordeev" />
<meta name="description" content="Hi, my name is Michael. I'm C# Developer and this is my personal website. Here you can find info about me, my projects and more. Check it out!" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="XFox111.NET" />
<meta property="og:url" content="//XFox111.NET/" />
<meta property="og:locale" content="en_US" />
<meta property="og:image" content="/images/me.png" />
<meta property="og:description" content="Hi, my name is Michael. I'm C# Developer and this is my personal website. Here you can find info about me, my projects and more. Check it out!" />
<meta property="og:title" content="Michael 'XFox' Gordeev - Personal website" />
}
}
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<nav>
<a asp-controller="Home" asp-action="Index" asp-area="">XFox111.NET</a>
<menu type="toolbar" id="main-menu" style="display:none">
<li><a asp-area="" asp-controller="Home" asp-action="Index">AboutMe();</a></li>
<li><a href="//xfox111.blogspot.com/" target="_blank">MyBlog();</a></li>
<li><a asp-area="" asp-controller="Resume" asp-action="Index">Resume();</a></li>
<li><a asp-area="" asp-controller="Projects" asp-action="Index">Projects();</a></li>
<li><a asp-area="" asp-controller="Gallery" asp-action="Index">Arts();</a></li>
<li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts();</a></li>
</menu>
<div>
<a asp-controller="Home" asp-action="SwitchLanguage" lang="ru">РУС &#xE12B;</a>
<a id="menu-toggle" onclick="ToggleMenu();">&#xE700;</a>
</div>
</nav>
<main onclick="document.querySelector('#main-menu').style.display = 'none'">
@RenderBody()
</main>
<footer>
<span class="comment">// Copyright &copy;@(DateTime.Today.Year) Michael "XFox" Gordeev</span>
</footer>
</body>
</html>
@@ -1,5 +1,4 @@
@using MyWebsite
@using MyWebsite.Models
@using MyWebsite.ViewModels
@using MyWebsite.Areas.Admin.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@@ -10,49 +10,49 @@ using MyWebsite.Areas.Projects.Models;
namespace MyWebsite.Areas.Projects.Controllers
{
[Area("Projects")]
public class FoxTubeController : ExtendedController
{
readonly DatabaseContext db;
readonly List<string> paths = new List<string>();
readonly List<string> files;
public FoxTubeController(DatabaseContext context) : base(context)
{
db = context;
[Area("Projects")]
public class FoxTubeController : ExtendedController
{
readonly List<string> paths = new List<string>();
readonly List<string> files;
private FoxTubeDatabaseContext FoxTubeDatabaseContext { get; set; }
Scan(Directory.GetCurrentDirectory() + "\\wwwroot\\assets\\FoxTube\\Screenshots\\" + CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName, paths);
public FoxTubeController(DatabaseContext context, FoxTubeDatabaseContext foxTubeDatabase) : base(context)
{
FoxTubeDatabaseContext = foxTubeDatabase;
Scan(Directory.GetCurrentDirectory() + "\\wwwroot\\assets\\FoxTube\\Screenshots\\" + CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName, paths);
for (int i = 0; i < paths.Count; i++)
paths[i] = paths[i].Substring(paths[i].IndexOf("Screenshots", System.StringComparison.OrdinalIgnoreCase));
for (int i = 0; i < paths.Count; i++)
paths[i] = paths[i].Substring(paths[i].IndexOf("Screenshots", System.StringComparison.OrdinalIgnoreCase));
files = paths.Select(i => i.Substring(i.LastIndexOf('\\') + 1)).ToList();
}
files = paths.Select(i => i.Substring(i.LastIndexOf('\\') + 1)).ToList();
}
public IActionResult Index() =>
View(new ScreenshotViewModel(db)
{
Paths = paths,
Names = files
});
public IActionResult Index() =>
View(new ScreenshotViewModel(Database)
{
Paths = paths,
Names = files
});
public IActionResult Screenshot(string id) =>
View(new ScreenshotViewModel(db)
{
Paths = paths,
Names = files,
Current = id
});
public IActionResult Screenshot(string id) =>
View(new ScreenshotViewModel(Database)
{
Paths = paths,
Names = files,
Current = id
});
public IActionResult Privacy() =>
View(new ResumeViewModel(db, CultureInfo.CurrentCulture));
public IActionResult Privacy() =>
View(new ResumeViewModel(FoxTubeDatabaseContext.PrivacyPolicies.Find(CultureInfo.CurrentCulture.TwoLetterISOLanguageName) ?? FoxTubeDatabaseContext.PrivacyPolicies.Find("en"), Database));
void Scan(string path, List<string> files)
{
foreach (string p in Directory.GetFiles(path))
files.Add(p);
void Scan(string path, List<string> files)
{
foreach (string p in Directory.GetFiles(path))
files.Add(p);
foreach (string p in Directory.GetDirectories(path))
Scan(p, files);
}
}
foreach (string p in Directory.GetDirectories(path))
Scan(p, files);
}
}
}
@@ -4,16 +4,16 @@ using System.Collections.Generic;
namespace MyWebsite.Areas.Projects.Models
{
public class ScreenshotViewModel : ViewModelBase
{
public List<string> Paths { get; set; }
public List<string> Names { get; set; }
public string Current { get; set; }
public class ScreenshotViewModel : ViewModelBase
{
public List<string> Paths { get; set; }
public List<string> Names { get; set; }
public string Current { get; set; }
public int Position => Names.IndexOf(Current);
public string Next => Names.Count == Position + 1 ? null : Names[Position + 1];
public string Previous => Position > 0 ? Names[Position - 1] : null;
public int Position => Names.IndexOf(Current);
public string Next => Names.Count == Position + 1 ? null : Names[Position + 1];
public string Previous => Position > 0 ? Names[Position - 1] : null;
public ScreenshotViewModel(DatabaseContext context) : base(context) { }
}
}
public ScreenshotViewModel(DatabaseContext context) : base(context) { }
}
}
@@ -1,100 +1,98 @@
@model ScreenshotViewModel
@{
ViewData["Title"] = "Meet FoxTube!";
Layout = "_Layout.cshtml";
ViewData["Title"] = "Meet FoxTube!";
Layout = "_Layout.cshtml";
}
<header>
<div id="mspb-c71suduiy4sa" class="9NCQQXJTDLFH"></div>
<div id="mspb-c71suduiy4sa" class="9NCQQXJTDLFH"></div>
</header>
<article>
<div class="description">
<div class="description">
<p>&#xE760; <a asp-action="Index" asp-controller="Projects" asp-area="" class="back">Back to other projects</a></p>
<p>&#xE760; <a asp-action="Index" asp-controller="Projects" asp-area="" class="back">Back to other projects</a></p>
<h1>Available on</h1>
<a>Requires Windows 10 April 2018 Update or higher</a>
<ul>
<li>PC</li>
<li>Surface Hub</li>
<li>HoloLens</li>
</ul>
<h1>Available on</h1>
<a>Requires Windows 10 April 2018 Update or higher</a>
<ul>
<li>PC</li>
<li>Surface Hub</li>
<li>HoloLens</li>
</ul>
<h1>Trailer</h1>
<div>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Mio9FbxmbhM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>
<h1>Trailer</h1>
<iframe class="video" src="https://www.youtube.com/embed/Mio9FbxmbhM" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
<h1>Description</h1>
<p>
YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos! Frequent updates will make you sure that all problems will be purged as soon as possible
</p>
<h1>Description</h1>
<p>
YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos! Frequent updates will make you sure that all problems will be purged as soon as possible
</p>
<h1>Features</h1>
<ul>
<li>New fresh view for YouTube</li>
<li>But so familiar...</li>
<li>Faster browsing: up to 40% faster than through You-know-who (Google Chrome)!</li>
<li>Nice dark theme for vampires</li>
<li>Picture-in-picture mode for hard workers</li>
<li>Download videos! Spread communism!*</li>
<li>8K support for big ones</li>
<li>Fox on logo!</li>
</ul>
<h1>Features</h1>
<ul>
<li>New fresh view for YouTube</li>
<li>But so familiar...</li>
<li>Faster browsing: up to 40% faster than through You-know-who (Google Chrome)!</li>
<li>Nice dark theme for vampires</li>
<li>Picture-in-picture mode for hard workers</li>
<li>Download videos! Spread communism!*</li>
<li>8K support for big ones</li>
<li>Fox on logo!</li>
</ul>
<h1>Screenshots</h1>
<div class="gallery">
@for (int i = 0; i < Model.Paths.Count; i++)
{
<a asp-action="Screenshot" asp-route-id="@Model.Names[i]"><img src="@Model.Paths[i]" title="@Model.Names[i]"></a>
}
</div>
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<h1>Screenshots</h1>
<div class="gallery">
@for (int i = 0; i < Model.Paths.Count; i++)
{
<a asp-action="Screenshot" asp-route-id="@Model.Names[i]"><img src="@Model.Paths[i]" title="@Model.Names[i]"></a>
}
</div>
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<h1>Useufl links</h1>
<ul>
<li><a asp-action="Privacy">Privacy policy</a></li>
<li><a target="_blank" href="//youtube.com/t/privacy">YouTube privacy policy</a></li>
<li><a target="_blank" href="//youtube.com/t/terms">YouTube terms of use</a></li>
<li><a target="_blank" href="//youtube.com/t/community_guidelines">YouTube community guidelines</a></li>
</ul>
<h1>Useufl links</h1>
<ul>
<li><a asp-action="Privacy">Privacy policy</a></li>
<li><a target="_blank" href="//youtube.com/t/privacy">YouTube privacy policy</a></li>
<li><a target="_blank" href="//youtube.com/t/terms">YouTube terms of use</a></li>
<li><a target="_blank" href="//youtube.com/t/community_guidelines">YouTube community guidelines</a></li>
</ul>
<h1>Credits</h1>
<h2>Demo footage content</h2>
<h3>Trailer</h3>
<ul>
<li><a target="_blank" href="//microsoft.com/">Microsoft</a> (Soundtrack: <a target="_blank" href="//www.youtube.com/watch?v=dwK422sLD-s">Introducing Microsoft Surface Laptop 2</a>)</li>
<li><a target="_blank" href="//www.youtube.com/user/skullkruncher13">JT Music</a> (Comparasion video: <a target="_blank" href="//www.youtube.com/watch?v=AGfa24afEBM">METRO EXODUS SONG by JT Music (feat. Andrea Storm Kaden)</a>)</li>
</ul>
<h3>Screenshots and live</h3>
<ul>
<li><a target="_blank" href="//windowscentral.com/">Windows Central</a></li>
<li><a target="_blank" href="//www.youtube.com/user/ouramazingspace/about">Space Videos</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCS3pqiugq53HFPYiWLPtdeA">MSReview</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UC6cqazSR6CnVMClY0bJI0Lg">BadComedian</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCf31Gf5nCU8J6eUlr7QSU0w">Marmok</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCK7OXr0m5mnM1z9p7n_Bwfw">DAGames</a></li>
<li><a target="_blank" href="//www.youtube.com/user/RandomEncountersEnt">Random Ecounters</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCuXYmUOJSbEH1x88WUV1aMg">TheNafig</a></li>
</ul>
<h1>Credits</h1>
<h2>Demo footage content</h2>
<h3>Trailer</h3>
<ul>
<li><a target="_blank" href="//microsoft.com/">Microsoft</a> (Soundtrack: <a target="_blank" href="//www.youtube.com/watch?v=dwK422sLD-s">Introducing Microsoft Surface Laptop 2</a>)</li>
<li><a target="_blank" href="//www.youtube.com/user/skullkruncher13">JT Music</a> (Comparasion video: <a target="_blank" href="//www.youtube.com/watch?v=AGfa24afEBM">METRO EXODUS SONG by JT Music (feat. Andrea Storm Kaden)</a>)</li>
</ul>
<h3>Screenshots and live</h3>
<ul>
<li><a target="_blank" href="//windowscentral.com/">Windows Central</a></li>
<li><a target="_blank" href="//www.youtube.com/user/ouramazingspace/about">Space Videos</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCS3pqiugq53HFPYiWLPtdeA">MSReview</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UC6cqazSR6CnVMClY0bJI0Lg">BadComedian</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCf31Gf5nCU8J6eUlr7QSU0w">Marmok</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCK7OXr0m5mnM1z9p7n_Bwfw">DAGames</a></li>
<li><a target="_blank" href="//www.youtube.com/user/RandomEncountersEnt">Random Ecounters</a></li>
<li><a target="_blank" href="//www.youtube.com/channel/UCuXYmUOJSbEH1x88WUV1aMg">TheNafig</a></li>
</ul>
<p>
© @(DateTime.Today.Year) Michael Gordeev<br />
© @(DateTime.Today.Year) YouTube LLC
</p>
</div>
<p>
© @(DateTime.Today.Year) Michael Gordeev<br />
© @(DateTime.Today.Year) YouTube LLC
</p>
</div>
</article>
@section Imports {
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Calibri:400,700,400italic,700italic" />
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<script src="https://storebadge.azureedge.net/src/badge-1.8.4.js"></script>
<script>
mspb({ productId: '9NCQQXJTDLFH', badgeType: 'large' }, function (badge)
{
document.getElementById('mspb-c71suduiy4sa').innerHTML = badge;
});
</script>
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Calibri:400,700,400italic,700italic" />
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<script src="https://storebadge.azureedge.net/src/badge-1.8.4.js"></script>
<script>
mspb({ productId: '9NCQQXJTDLFH', badgeType: 'large' }, function (badge)
{
document.getElementById('mspb-c71suduiy4sa').innerHTML = badge;
});
</script>
}
@@ -1,30 +1,49 @@
@model ResumeViewModel
@{
ViewData["Title"] = "Privacy policy";
Layout = "_Layout.cshtml";
ViewData["Title"] = "Privacy policy";
Layout = "_Layout.cshtml";
}
<header>
<p>&#xE760; <a asp-action="Index">Back to description</a></p>
<h1>FoxTube privacy policy</h1>
<p>Last update: @Model?.Resume.LastUpdate</p>
&#xE760; <a asp-action="Index">Back to description</a>
<h1>FoxTube privacy policy</h1>
Last update: @Model?.Resume.LastUpdate
</header>
<article>
@Html.Raw(Model?.Resume.Content)
@Html.Raw(Model?.Resume.Content)
</article>
@section Imports {
<style type="text/css">
header, article {
margin: 0px 50px;
}
header a {
color: black;
text-decoration: none;
}
header a:hover {
text-decoration: underline;
}
</style>
<style type="text/css">
article
{
margin: 0px 50px;
}
header
{
margin: 16px 50px;
}
header a
{
color: black;
text-decoration: none;
}
header a:hover
{
text-decoration: underline;
}
@@media only screen and (max-width: 500px)
{
header, article
{
margin-right: 20px;
margin-left: 20px;
}
}
</style>
}
@@ -1,12 +1,10 @@
@using System.IO
@using System.Globalization
@model ScreenshotViewModel
@model ScreenshotViewModel
@{
ViewData["Title"] = "Screenshot";
Layout = "_Layout.cshtml";
}
<article class="image-overview-block">
<header>
<p class="controls">
&#xE15C; <a asp-action="Index" class="back">Back to description</a>
@if (Model.Previous != null)
@@ -20,41 +18,44 @@
<a asp-action="Screenshot" asp-route-id="@Model.Next" class="back">Next</a>
}
</p>
<p class="title">
<p>
<b>@Model.Current</b>
</p>
</header>
<img src="@Model.Paths[Model.Position]" id="image" onclick="ToggleImageSize();"/>
<article class="image-overview-block">
<img src="@Model.Paths[Model.Position]" id="image" onclick="ToggleImageSize();" />
</article>
@section Imports {
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<style type="text/css">
#image {
max-height: initial;
#image
{
max-height: 75vh;
}
.controls {
display: inline-block;
}
.title {
float: right;
header
{
display: grid;
grid-template-columns: 1fr auto;
margin: 0px 20px;
}
</style>
<script type="text/javascript">
function ToggleImageSize()
{
var image = document.getElementById("image");
function ToggleImageSize()
{
var image = document.getElementById("image");
if (image.style.cursor == "zoom-out")
image.style = "";
else
{
image.style.maxHeight = "none";
image.style.maxWidth = "none";
image.style.cursor = "zoom-out";
}
}
if (image.style.cursor == "zoom-out")
image.style = "";
else
{
image.style.maxHeight = "initial";
image.style.maxWidth = "initial";
image.style.cursor = "zoom-out";
}
}
</script>
}
@@ -2,91 +2,89 @@
<!DOCTYPE html>
<html>
<head>
<title>@ViewData["Title"] - FoxTube - XFox111.NET</title>
<base href="~/assets/FoxTube/" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<title>@ViewData["Title"] - FoxTube - XFox111.NET</title>
<base href="~/assets/FoxTube/" />
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="~/css/Socicon.css" />
<link rel="stylesheet" type="text/css" href="FoxTube.css" />
<link rel="stylesheet" href="https://s3.amazonaws.com/icomoon.io/114779/Socicon/style.css?u8vidh" />
<link rel="stylesheet" type="text/css" href="~/css/Fonts.css" />
<link rel="stylesheet" type="text/css" href="FoxTube.css" />
<script type="text/javascript">
function ToggleMenu()
{
var menu = document.getElementById("main-menu");
<script type="text/javascript">
function ToggleMenu()
{
var menu = document.querySelector("menu");
if (menu.style.display == "none")
menu.style.display = "initial";
else
menu.style.display = "none";
}
</script>
if (menu.style.display == "none")
menu.style.display = "initial";
else
menu.style.display = "none";
}
</script>
@RenderSection("Imports", false)
@RenderSection("Imports", false)
@if (IsSectionDefined("OpenGraph"))
RenderSection("OpenGraph");
else
{
<meta name="author" content="Michael 'XFox' Gordeev">
<meta name="description" content="YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos!">
@if (IsSectionDefined("OpenGraph"))
RenderSection("OpenGraph");
else
{
<meta name="author" content="Michael 'XFox' Gordeev">
<meta name="description" content="YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos!">
<meta property="og:image" content="FoxTubeLogo.png">
<meta property="og:video" content="//www.youtube.com/embed/Mio9FbxmbhM">
<meta property="og:video" content="https://www.youtube.com/embed/Mio9FbxmbhM">
<meta property="og:video" content="https://www.youtube.com/v/Mio9FbxmbhM">
<meta property="ya:ovs:allow_embed" content="true" />
<meta property="og:type" content="article">
<meta property="og:locale" content="en_US">
<meta property="og:description" content="YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos!">
<meta property="og:title" content="Meet FoxTube! - New YouTube client for Windows 10">
}
<meta property="og:image" content="/assets/FoxTube/Logo.svg">
<meta property="og:site_name" content="FoxTube - New YouTube client for Windows 10" />
<meta property="og:video" content="//www.youtube.com/embed/Mio9FbxmbhM">
<meta property="og:video" content="https://www.youtube.com/embed/Mio9FbxmbhM">
<meta property="og:video" content="https://www.youtube.com/v/Mio9FbxmbhM">
<meta property="ya:ovs:allow_embed" content="true" />
<meta property="og:type" content="article">
<meta property="og:locale" content="en_US">
<meta property="og:description" content="YouTube client for Windows 10 family devices. It's fast and convenient. It also supports live streams and 8K videos!">
<meta property="og:title" content="Meet FoxTube! - New YouTube client for Windows 10">
}
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<nav>
<img class="logo" src="Logo.svg" />
<a asp-action="Index">
<b>FoxTube</b><br />
YouTube client for Windows 10
</a>
<nav>
<img class="logo" src="Logo.svg" />
<a asp-action="Index">
<b>FoxTube</b><br />
<span>YouTube client for Windows 10</span>
</a>
<menu type="toolbar" id="main-menu" style="display:none">
<li><a asp-area="" asp-controller="Home" asp-action="Index">Home();</a></li>
<li><a asp-area="" asp-controller="Resume" asp-action="Index">MyResume();</a></li>
<li><a asp-area="" asp-controller="Projects" asp-action="Index">Projects();</a></li>
<li><a asp-area="" asp-controller="Gallery" asp-action="Index">Arts();</a></li>
<li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts();</a></li>
</menu>
<menu type="toolbar" style="display:none">
<partial name="~/Views/Shared/TopBarMenu.cshtml" />
</menu>
<p>
<a asp-controller="Home" asp-action="Index" asp-area="">XFox111.NET</a><br />
<a asp-controller="Home" asp-action="SwitchLanguage" lang="ru">РУС &#xE12B;</a>
<a id="menu-toggle" onclick="ToggleMenu();">&#xE700;</a>
</p>
</nav>
<p>
<a asp-controller="Home" asp-action="Index" asp-area="">XFox111.NET</a><br />
<a asp-controller="Home" asp-action="SwitchLanguage" lang="ru">РУС &#xE12B;</a>
<a id="menu-toggle" onclick="ToggleMenu();">&#xE700;</a>
</p>
</nav>
<main>
@RenderBody()
</main>
<main onclick="document.querySelector('menu').style.display = 'none'">
@RenderBody()
</main>
@{
if (IsSectionDefined("Footer"))
RenderSection("Footer");
else
{
<footer>
<span class="comment">// Copyright &copy;@(DateTime.Today.Year) Michael "XFox" Gordeev</span>
@{
if (IsSectionDefined("Footer"))
RenderSection("Footer");
else
{
<footer>
<span class="comment">// Copyright &copy;@(DateTime.Today.Year) Michael "XFox" Gordeev</span>
<div>
@foreach (LinkModel link in Model.Links.Where(i => i.DisplayInFooter).OrderBy(i => i.Order))
{
<a class="socicon-@(link.Name)" href="@(link.Url)" target="_blank" title="@(link.Title)"></a>
}
</div>
</footer>
}
}
<div>
@foreach (LinkModel link in Model.Links.Where(i => i.DisplayInFooter).OrderBy(i => i.Order))
{
<a class="socicon-@(link.Name)" href="@(link.Url)" target="_blank" title="@(link.Title)"></a>
}
</div>
</footer>
}
}
</body>
</html>
@@ -0,0 +1,14 @@
@model ResumeViewModel
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewData["Title"] = "GUT.Schedule privacy policy";
}
<header>
<h1>GUT.Schedule privacy policy</h1>
<p>Last update: @Model?.Resume?.LastUpdate</p>
</header>
<article>
@Html.Raw(Model?.Resume?.Content)
</article>
@@ -3,4 +3,4 @@
@using MyWebsite.Areas.Projects.Models
@using MyWebsite.Models
@using MyWebsite.ViewModels
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@@ -39,11 +39,15 @@ namespace MyWebsite.Controllers
CredentialModel user = Database.Users.FirstOrDefault(i => i.Email == model.Credential.Email);
if (user == null || !Encryptor.VerifyHash(model?.Credential.Password, user.Password))
{
if (!Database.Users.Any())
goto Authorize;
ModelState.AddModelError("Authorization error", "Invaild e-mail or password");
return View(new CredentialViewModel(Database, model));
}
Claim claim = new Claim(ClaimsIdentity.DefaultNameClaimType, user.Email);
Authorize:
Claim claim = new Claim(ClaimsIdentity.DefaultNameClaimType, user?.Email ?? "root");
ClaimsIdentity id = new ClaimsIdentity(new Claim[] { claim }, "ApplicationCookie", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id)).ConfigureAwait(false);
@@ -56,16 +60,5 @@ namespace MyWebsite.Controllers
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme).ConfigureAwait(false);
return RedirectToAction("Login", "Admin");
}
[AllowAnonymous]
public bool ResetPassword(string id)
{
CredentialModel user = Database.Users.Find("michael.xfox@outlook.com");
user.Password = Encryptor.ComputeHash(id);
Database.Users.Update(user);
Database.SaveChanges();
return true;
}
}
}
@@ -8,6 +8,8 @@ namespace MyWebsite.Models.Databases
public DbSet<MetricsPackage> Metrics { get; set; }
public DbSet<Message> Messages { get; set; }
public DbSet<Changelog> Changelogs { get; set; }
public DbSet<ResumeModel> PrivacyPolicies { get; set; }
public FoxTubeDatabaseContext(DbContextOptions<FoxTubeDatabaseContext> options) : base(options) =>
Database.EnsureCreated();
@@ -0,0 +1,13 @@
using Microsoft.EntityFrameworkCore;
namespace MyWebsite.Models.Databases
{
public class GUTScheduleDatabaseContext : DbContext
{
public DbSet<ResumeModel> PrivacyPolicies { get; set; }
public DbSet<CustomData> OffsetDates { get; set; }
public GUTScheduleDatabaseContext(DbContextOptions<GUTScheduleDatabaseContext> options) : base(options) =>
Database.EnsureCreated();
}
}
+1 -2
View File
@@ -9,7 +9,7 @@ namespace MyWebsite.Models
public class ImageModel
{
[Key]
[Column(TypeName = "varchar(20)")]
[Column(TypeName = "varchar(255)")]
[DisplayName("File name")]
public string FileName { get; set; }
@@ -27,7 +27,6 @@ namespace MyWebsite.Models
[DisplayName("Description")]
public string Description => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ru" && !string.IsNullOrWhiteSpace(RussianDescription) ? RussianDescription : EnglishDescription;
[Required]
[Column(TypeName = "text")]
[DisplayName("Description (en)")]
public string EnglishDescription { get; set; }
+10 -4
View File
@@ -1,4 +1,5 @@
using System.ComponentModel;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Globalization;
@@ -10,8 +11,14 @@ namespace MyWebsite.Models
{
[Key]
[Required]
[DisplayName("ID (Order)")]
public decimal Id { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[DisplayName("ID")]
public Guid Id { get; set; }
[Required]
[Column(TypeName = "int")]
[DisplayName("Order")]
public int Order { get; set; }
[DisplayName("Title")]
public string Title => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ru" && !string.IsNullOrWhiteSpace(RussianTitle) ? RussianTitle : EnglishTitle;
@@ -42,7 +49,6 @@ namespace MyWebsite.Models
[DisplayName("Link text caption")]
public string LinkCaption => CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "ru" && !string.IsNullOrWhiteSpace(RussianTitle) ? RussianLinkCaption : EnglishLinkCaption;
[Required]
[Column(TypeName = "varchar(50)")]
[DisplayName("Link text caption (en)")]
public string EnglishLinkCaption { get; set; }
+15 -25
View File
@@ -1,36 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<AssemblyName>XFox111dotNET</AssemblyName>
<Authors>Michael "XFox" Gordeev</Authors>
<Company>FoxDev Studio</Company>
<Product>XFox111.NET</Product>
<Description>This is my personal website written in ASP.NET MVC</Description>
<Copyright>©2020 Michael "XFox" Gordeev</Copyright>
<PackageProjectUrl>https://xfox111.net/</PackageProjectUrl>
<RepositoryUrl>https://github.com/xfox111/cvwebsite</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<Compile Remove="wwwroot\projects-assets\**" />
<Content Remove="wwwroot\projects-assets\**" />
<EmbeddedResource Remove="wwwroot\projects-assets\**" />
<None Remove="wwwroot\projects-assets\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Areas\Admin\NewFile.txt" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.2" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.1.1" />
<PackageReference Include="Select.HtmlToPdf.NetCore" Version="19.2.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\assets\FoxTube\Screenshots\" />
</ItemGroup>
</Project>
</Project>
-13
View File
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>
<Controller_SelectedScaffolderCategoryPath>root/Controller</Controller_SelectedScaffolderCategoryPath>
<WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
<WebStackScaffolding_IsLayoutPageSelected>False</WebStackScaffolding_IsLayoutPageSelected>
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>False</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
<WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
<WebStackScaffolding_ViewDialogWidth>600</WebStackScaffolding_ViewDialogWidth>
</PropertyGroup>
</Project>
+4 -4
View File
@@ -10,13 +10,10 @@ using MyWebsite.Models.Databases;
namespace MyWebsite
{
// TODO: Add reordering for contact links
// TODO: Complete project admin page
// TODO: Complete artworks admin page
// TODO: FoxTube API admin page
// TODO: Complete homepage
// TODO: Complete FoxTube page
// TODO: Add localization system
// TODO: Add blog
// TODO: Rid of JavaScript (use Blazor)
public class Startup
{
@@ -36,6 +33,9 @@ namespace MyWebsite
services.AddDbContext<FoxTubeDatabaseContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("FoxTubeDB")));
services.AddDbContext<GUTScheduleDatabaseContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("GUTScheduleDB")));
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
options.LoginPath = new PathString("/Admin/Login"));
@@ -8,6 +8,9 @@ namespace MyWebsite.ViewModels
{
public ResumeModel Resume { get; }
public ResumeViewModel(DatabaseContext context, CultureInfo language) : base(context) =>
Resume = context.Resume.Find(language?.Name) ?? context.Resume.Find("en-US");
Resume = context.Resume.Find(language?.TwoLetterISOLanguageName) ?? context.Resume.Find("en");
public ResumeViewModel(ResumeModel model, DatabaseContext context) : base(context) =>
Resume = model;
}
}
@@ -10,6 +10,6 @@ namespace MyWebsite.ViewModels
public IEnumerable<LinkModel> Links { get; }
public ViewModelBase(DatabaseContext context) =>
Links = context?.Links.ToList();
Links = context?.Links.OrderBy(i => i.Order);
}
}
+5 -5
View File
@@ -6,23 +6,23 @@
<h1>Administration</h1>
</header>
<article>
<p class="admin-menu">
<article class="admin-menu">
<p>
<a asp-action="Gallery" class="comment">// Artworks</a><br />
<a asp-action="Projects" class="comment">// Projects</a><br />
<a asp-action="Badges" class="comment">// Badges</a><br />
<a asp-action="Resume" class="comment">// Resume</a><br />
<a asp-action="Contacts" class="comment">// Contact links</a>
</p>
<p class="admin-menu">
<p>
<a asp-action="FoxTube" class="comment">// FoxTube API</a><br />
<a asp-action="GUTSchedule" class="comment">// GUT.Schedule API</a>
</p>
<p>
<a asp-action="Credential" class="logout">// Change credential information</a>
<a asp-action="Credential" class="comment logout">// Change credential information</a>
</p>
<p>
<a asp-action="Logout" class="logout">&#xE875; Logout</a>
<a asp-action="Logout" class="comment logout">&#xE875; Logout</a>
</p>
</article>
@@ -4,24 +4,22 @@
}
<header>
<p>
@if (Model.Previous != null)
{
@:&#xE760;
<a asp-action="Details" asp-route-id="@Model.Previous">Previous</a>
@:|
}
&#xE8B9; <a asp-action="Index" asp-controller="Gallery">All artworks</a>
@if (Model.Next != null)
{
@:| &#xE761;
<a asp-action="Details" asp-route-id="@Model.Next">Next</a>
}
</p>
@if (Model.Previous != null)
{
@:&#xE760;
<a asp-action="Details" asp-route-id="@Model.Previous">Previous</a>
@:|
}
&#xE8B9; <a asp-action="Index" asp-controller="Gallery">All artworks</a>
@if (Model.Next != null)
{
@:| &#xE761;
<a asp-action="Details" asp-route-id="@Model.Next">Next</a>
}
</header>
<article class="image-overview-block">
<img src="~/images/Gallery/@Model.Current?.FileName" onclick="ToggleImageSize();" id="image" />
<img src="~/images/Gallery/@Model.Current?.FileName" onclick="ToggleImageSize();" />
<div>
<h1>@Model.Current?.Title</h1>
@@ -32,13 +30,14 @@
</div>
</article>
@section Imports {
@section Imports
{
<link rel="stylesheet" type="text/css" href="~/css/Gallery.css" />
<script type="text/javascript">
function ToggleImageSize()
{
var image = document.getElementById("image");
var image = document.querySelector("img");
if (image.style.cursor == "zoom-out")
image.style = "";
@@ -5,14 +5,14 @@
<header>
<h1>My resume</h1>
<p>Last update: @Model?.Resume.LastUpdate</p>
<p>Last update: @Model?.Resume?.LastUpdate</p>
<a class="comment" asp-action="Download">// Download CV (.pdf) &#xE118;</a><br />
<a class="comment" asp-action="Print">// Print CV &#xE749;</a>
</header>
<article>
@Html.Raw(Model?.Resume.Content)
@Html.Raw(Model?.Resume?.Content)
</article>
@section Footer
@@ -12,6 +12,7 @@
<base href="~/assets/Construction/" />
<link rel="stylesheet" type="text/css" href="Construction.css">
<link rel="stylesheet" type="text/css" href="~/css/Fonts.css">
<script type="text/javascript" src="Construction.js"></script>
<meta name="author" content="Michael 'XFox' Gordeev">
@@ -89,7 +90,7 @@
@foreach (LinkModel item in Model.Links.Where(i => i.Name.Belongs("outlook", "linkedin", "vkontakte", "twitter", "github")))
{
<p>@item.Title: <a href="@item.Url">@((item.Url.ToString().StartsWith("mailto:") ? "" : "https:") + item.Url)</a></p>
<p>@item.Title: <a href="@item.Url" target="_blank">@((item.Url.ToString().StartsWith("mailto:") ? "" : "https:") + item.Url)</a></p>
}
<br />
@@ -5,8 +5,8 @@
<!-- TODO: Make Error page-->
<header>
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h1>Error</h1>
<h2>An error occurred while processing your request.</h2>
</header>
<article>
+18 -1
View File
@@ -8,6 +8,23 @@
<article>
<p>
Homepage
Hi guys! This is my website. And this is its home page. Usually, homepages should look as much glorious and cool as they can. But for some inspirational reasons I've done everything except homepage.
</p>
<p>
Well, maybe not everything... But the most of it. If I could I would leave it offline for a few more <s>years</s> <s>month</s> time. But I need it online now, so here we go. <br />
Lets consider it as 0.1.2020.03.08.666 prerelease beta technical preview demo pre-RTM version.
</p>
<p>
So you can lurk around and check other pages. I'm pretty sure they should be fine.
</p>
<dl>
<dt>Cheers,</dt>
<dd>Michael "XFox" Gordeev</dd>
</dl>
<p hidden>
But anyway I should tell some more about it, shouldn't I?
</p>
<p hidden>
My name is Michael, I'm C# Developer and CS student in Saint Petersburg (the russian one:)
</p>
</article>
@@ -14,7 +14,7 @@
<article>
@if (Model.Projects.Count() > 0)
{
@foreach (ProjectModel project in Model.Projects)
@foreach (ProjectModel project in Model.Projects.OrderBy(i => i.Order))
{
<div class="project-item">
<div>
@@ -40,6 +40,7 @@
}
</article>
@section Imports {
@section Imports
{
<link rel="stylesheet" type="text/css" href="~/css/Projects.css" />
}
@@ -0,0 +1,6 @@
<li><a asp-area="" asp-controller="Home" asp-action="Index">AboutMe();</a></li>
<li hidden><a href="//xfox111.blogspot.com/" target="_blank">MyBlog();</a></li>
<li><a asp-area="" asp-controller="Resume" asp-action="Index">MyResume();</a></li>
<li><a asp-area="" asp-controller="Projects" asp-action="Index">Projects();</a></li>
<li><a asp-area="" asp-controller="Gallery" asp-action="Index">Arts();</a></li>
<li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts();</a></li>
@@ -6,12 +6,13 @@
<link rel="shortcut icon" href="~/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="~/css/Style.css" />
<link rel="stylesheet" type="text/css" href="~/css/Socicon.css" />
<link rel="stylesheet" type="text/css" href="~/css/Fonts.css" />
<link rel="stylesheet" href="https://s3.amazonaws.com/icomoon.io/114779/Socicon/style.css?u8vidh" />
<script type="text/javascript">
function ToggleMenu()
{
var menu = document.getElementById("main-menu");
var menu = document.querySelector("nav menu");
if (menu.style.display == "none")
menu.style.display = "initial";
@@ -47,12 +48,8 @@
<nav>
<a asp-controller="Home" asp-action="Index" asp-area="">XFox111.NET</a>
<menu type="toolbar" id="main-menu" style="display:none">
<li><a asp-area="" asp-controller="Home" asp-action="Index">AboutMe();</a></li>
<li><a asp-area="" asp-controller="Resume" asp-action="Index">Resume();</a></li>
<li><a asp-area="" asp-controller="Projects" asp-action="Index">Projects();</a></li>
<li><a asp-area="" asp-controller="Gallery" asp-action="Index">Arts();</a></li>
<li><a asp-area="" asp-controller="Contacts" asp-action="Index">Contacts();</a></li>
<menu type="toolbar" style="display:none">
<partial name="~/Views/Shared/TopBarMenu.cshtml" />
</menu>
<div>
@@ -61,7 +58,7 @@
</div>
</nav>
<main>
<main onclick="document.querySelector('nav menu').style.display = 'none'">
@RenderBody()
</main>
@@ -1,9 +0,0 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
+2 -1
View File
@@ -9,6 +9,7 @@
"AllowedHosts": "*",
"ConnectionStrings": {
"MainDB": "Server=(localdb)\\mssqllocaldb;Database=xfox111;Trusted_Connection=True;",
"FoxTubeDB": "Server=(localdb)\\mssqllocaldb;Database=foxtube;Trusted_Connection=True;"
"FoxTubeDB": "Server=(localdb)\\mssqllocaldb;Database=foxtube;Trusted_Connection=True;",
"GUTScheduleDB": "Server=(localdb)\\mssqllocaldb;Database=gutSchedule;Trusted_Connection=True;"
}
}
+47
View File
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!--Redirects-->
<system.webServer>
<rewrite>
<rules>
<!--Legacy redirects-->
<rule name="GutSchedule API redirect" stopProcessing="true">
<match url="schedule_offset.txt" />
<action type="Redirect" url="https://xfox111.net/API/GUTSchedule/SemesterOffsetDay" redirectType="Permanent" appendQueryString="false" />
</rule>
<rule name="GUT.Schedule Privacy policy" stopProcessing="true">
<match url="Projects/GUTSchedule/PrivacyPolicy.txt" />
<action type="Redirect" url="https://xfox111.net/Projects/GUTSchedule/PrivacyPolicy" redirectType="Permanent" appendQueryString="false" />
</rule>
<rule name="FoxTubr Privacy policy" stopProcessing="true">
<match url="Projects/FoxTube/PrivacyPolicy.txt" />
<action type="Redirect" url="https://xfox111.net/Projects/FoxTube/PrivacyPolicy" redirectType="Permanent" appendQueryString="false" />
</rule>
<!--/Legacy redirects-->
<!--Website maintainence redirect-->
<rule name="Construction redirect" stopProcessing="true" enabled="false">
<match url="^(?!Admin|API|Construction|css|assets|fonts|images)" />
<action type="Redirect" url="https://xfox111.net/Construction" redirectType="Temporary" appendQueryString="false" />
</rule>
<!--\Website maintainence redirect-->
</rules>
</rewrite>
</system.webServer>
<!--/Redirects-->
<location path="." inheritInChildApplications="false" allowOverride="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\XFox111dotNET.exe" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
</system.webServer>
<system.web>
<trust level="Full" />
</system.web>
</location>
<system.web>
<compilation defaultLanguage="c#" />
<globalization fileEncoding="utf-8" />
</system.web>
</configuration>
<!--ProjectGuid: 9fb2b925-dc18-4081-ac91-96f2c49415f9-->
@@ -1,19 +1,4 @@
/* Declaring fonts */
@font-face
{
font-family: 'Consolas';
src: url("/fonts/Consolas/consolas.eot");
src: url("/fonts/Consolas/consolas.eot?#iefix") format("embedded-opentype"), url("/fonts/Consolas/consolas.otf") format("opentype"), url("/fonts/Consolas/consolas.svg") format("svg"), url("/fonts/Consolas/consolas.ttf") format("truetype"), url("/fonts/Consolas/consolas.woff") format("woff"), url("/fonts/Consolas/consolas.woff2") format("woff2");
}
@font-face
{
font-family: 'Segoe MDL2 Assets';
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot");
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot?#iefix") format("embedded-opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.otf") format("opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.svg") format("svg"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.ttf") format("truetype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff") format("woff"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff2") format("woff2");
}
/* Header */
/* Header */
nav
{
user-select: none;
@@ -68,6 +53,7 @@ nav
line-height: 26px;
text-align: center;
}
nav > div:last-child select
{
background-color: #333337;
@@ -78,9 +64,10 @@ nav
height: 21px;
margin: 2px 0px;
}
nav > div:last-child img
{
height: 100%;
height: 26px;
}
/* Body */
@@ -95,7 +82,7 @@ body
color: white;
font-size: 9pt;
margin: 0px;
font-family: 'Segoe UI Symbol';
font-family: 'SegoeUISymbol';
overflow: auto;
display: grid;
height: 100vh;
@@ -103,7 +90,7 @@ body
main
{
font-family: Consolas;
font-family: 'Consolas';
margin: 50px 0px 50px 12px;
}
@@ -111,6 +98,7 @@ main
{
margin: 0px;
display: none;
white-space: nowrap;
}
a
@@ -223,3 +211,38 @@ footer
{
content: '\1F7A8';
}
@media only screen and (max-width: 560px)
{
nav > div:last-child
{
height: initial;
grid-template-columns: initial;
}
nav > div:last-child select
{
width: initial;
margin: 0px 5px;
}
nav > div > span
{
text-align: start !important;
}
main
{
margin-top: 110px;
}
.git-btn
{
min-width: 17px;
}
.git-btn > span
{
display: none;
}
}
@@ -1,19 +1,4 @@
/* Declaring fonts */
@font-face
{
font-family: 'Consolas';
src: url("/fonts/Consolas/consolas.eot");
src: url("/fonts/Consolas/consolas.eot?#iefix") format("embedded-opentype"), url("/fonts/Consolas/consolas.otf") format("opentype"), url("/fonts/Consolas/consolas.svg") format("svg"), url("/fonts/Consolas/consolas.ttf") format("truetype"), url("/fonts/Consolas/consolas.woff") format("woff"), url("/fonts/Consolas/consolas.woff2") format("woff2");
}
@font-face
{
font-family: 'Segoe MDL2 Assets';
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot");
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot?#iefix") format("embedded-opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.otf") format("opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.svg") format("svg"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.ttf") format("truetype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff") format("woff"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff2") format("woff2");
}
/* Header styles */
/* Header styles */
nav
{
display: grid;
@@ -70,40 +55,6 @@ menu
display: block;
}
/* Adaptive code */
@media only screen and (min-width: 1150px)
{
menu
{
display: initial !important;
grid-row: 1;
grid-column: 3;
margin: 0px;
align-self: end;
margin-bottom: 3px;
}
menu li
{
display: inline-block;
margin-right: 10px;
margin-top: 0px;
}
#menu-toggle
{
display: none;
}
}
@media only screen and (max-width: 700px) {
body
{
margin-top: 112px !important;
height: calc(100vh - 112px) !important;
}
}
/* Body styles */
html
{
@@ -112,7 +63,7 @@ html
body
{
font-family: 'Consolas', 'Segoe MDL2 Assets';
font-family: 'Consolas', 'SegoeMDL2Assets';
overflow: auto;
margin: 0px;
margin-top: 84px;
@@ -123,7 +74,7 @@ body
main
{
font-family: 'Calibri', 'Segoe MDL2 Assets';
font-family: 'Calibri', 'SegoeMDL2Assets';
}
.back
@@ -152,6 +103,18 @@ article
color: #57a64a !important;
}
.video
{
max-width: 560px;
height: 315px;
width: 100%;
}
*[hidden]
{
display: none;
}
/* Footer styles */
footer
{
@@ -172,3 +135,56 @@ footer
{
color: orangered;
}
/* Adaptive code */
@media only screen and (min-width: 1150px)
{
menu
{
display: initial !important;
grid-row: 1;
grid-column: 3;
margin: 0px;
align-self: end;
margin-bottom: 3px;
}
menu li
{
display: inline-block;
margin-right: 10px;
margin-top: 0px;
}
#menu-toggle
{
display: none;
}
}
@media only screen and (max-width: 700px) and (min-width: 480px)
{
body
{
margin-top: 112px !important;
height: calc(100vh - 112px) !important;
}
}
@media only screen and (max-width: 480px)
{
nav > a > span
{
display: none;
}
.video
{
height: 240px !important;
}
}
nav > p > a:nth-last-child(2)
{
visibility: hidden;
}
+75 -37
View File
@@ -1,7 +1,7 @@
input
input:not([type="checkbox"])
{
padding: 10px;
border-radius: 10px;
border-radius: 5px;
border: 1px solid black;
width: 100%;
box-sizing: border-box;
@@ -12,32 +12,84 @@ select
{
padding: 10px;
border: 1px solid black;
border-radius: 10px;
border-radius: 5px;
width: 100%;
-moz-appearance: none; /* Firefox */
-webkit-appearance: none; /* Safari and Chrome */
}
input:invalid
{
border: 3px solid red;
}
input[type="submit"],
input[type="button"],
button
{
margin: 10px;
border-radius: 10px;
border-radius: 5px;
border: 0px;
padding: 10px 20px;
background-color: #343434;
color: white;
cursor: pointer;
}
input[type="submit"]:disabled,
input[type="button"]:disabled,
button:disabled
{
background-color: gray;
cursor: initial;
}
input[type="submit"]:hover:not(:disabled),
input[type="button"]:hover:not(:disabled),
button:hover:not(:disabled)
{
background-color: #505050;
}
input[type="submit"]:active,
input[type="button"]:active,
button:active
{
background-color: black;
}
input[type="submit"][required],
input[type="button"][required]
{
background-color: red;
}
input[type="submit"][required]:hover,
input[type="button"][required]:hover
{
background-color: rgb(200, 0, 0);
}
input[type="submit"][required]:active,
input[type="button"][required]:active
{
background-color: darkred;
}
input[readonly]
{
background-color: lightgray;
}
textarea
{
resize: none;
width: 100%;
border-radius: 10px;
border-radius: 5px;
border: 1px solid black;
padding: 10px;
box-sizing: border-box;
height: 200px;
font-family: Consolas;
height: 68vh;
font-family: 'Consolas';
}
.select-container::after
@@ -60,17 +112,17 @@ textarea
form
{
max-width: 50%;
max-width: 500px;
width: 100%;
}
.admin-menu a
.admin-menu > p a
{
font-size: 16pt;
}
.logout, .logout:link, .logout:link:visited
.comment.logout
{
font-size: 16pt;
color: red !important;
}
@@ -94,48 +146,34 @@ table
width: 100%;
}
.form-group input
{
width: auto;
}
.text-danger
{
text-decoration: solid;
color: red;
}
.btn
{
background-color: #343434;
color: white;
}
.btn-danger
{
background-color: red;
color: white;
}
.checkbox
{
width: auto;
}
.readonly
{
background-color: lightgray;
}
.reorder-arrow:link
{
text-decoration: none;
}
@media only screen and (max-width: 700px)
@media only screen and (max-width: 1080px)
{
form
.hide-l1
{
max-width: initial;
display: none;
}
}
@media only screen and (max-width: 850px)
{
.hide-l2
{
display: none;
}
}
@@ -50,4 +50,12 @@
footer span a:hover
{
color: #d69d85;
}
}
@media only screen and (max-width: 500px)
{
footer
{
padding: 20px;
}
}
+23
View File
@@ -0,0 +1,23 @@
@font-face
{
font-family: 'Consolas';
src: local("Consolas"), url("/fonts/Consolas/consolas.eot"), url("/fonts/Consolas/consolas.eot?#iefix") format("embedded-opentype"), url("/fonts/Consolas/consolas.otf") format("opentype"), url("/fonts/Consolas/consolas.svg") format("svg"), url("/fonts/Consolas/consolas.ttf") format("truetype"), url("/fonts/Consolas/consolas.woff") format("woff"), url("/fonts/Consolas/consolas.woff2") format("woff2");
}
@font-face
{
font-family: 'SegoeMDL2Assets';
src: local("Segoe MDL2 Assets"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot?#iefix") format("embedded-opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.otf") format("opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.svg") format("svg"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.ttf") format("truetype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff") format("woff"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff2") format("woff2");
}
@font-face
{
font-family: 'Calibri';
src: local("Calibri"), url("/fonts/Calibri/calibri.eot"), url("/fonts/Calibri/calibri.eot?#iefix") format("embedded-opentype"), url("/fonts/Calibri/calibri.otf") format("opentype"), url("/fonts/Calibri/calibri.svg") format("svg"), url("/fonts/Calibri/calibri.ttf") format("truetype"), url("/fonts/Calibri/calibri.woff") format("woff"), url("/fonts/Calibri/calibri.woff2") format("woff2");
}
@font-face
{
font-family: 'SegoeUISymbol';
src: local("Segoe UI Symbol"), url("/fonts/Segoe UI Symbol/segoeUISymbol.eot"), url("/fonts/Segoe UI Symbol/segoeUISymbol.eot?#iefix") format("embedded-opentype"), url("/fonts/Segoe UI Symbol/segoeUISymbol.otf") format("opentype"), url("/fonts/Segoe UI Symbol/segoeUISymbol.svg") format("svg"), url("/fonts/Segoe UI Symbol/segoeUISymbol.ttf") format("truetype"), url("/fonts/Segoe UI Symbol/segoeUISymbol.woff") format("woff"), url("/fonts/Segoe UI Symbol/segoeUISymbol.woff2") format("woff2");
}
+26 -17
View File
@@ -14,6 +14,27 @@
transform: scale(1.1);
}
/* Image details page styles */
.image-overview-block img
{
max-height: 50vh;
max-width: 100%;
float: left;
cursor: zoom-in;
}
.image-overview-block > div,
.image-overview-block > form
{
display: inline-block;
margin-left: 20px;
}
.image-overview-block h1
{
margin-bottom: 0px;
}
/* Adaptive code */
@media only screen and (max-width: 700px)
{
@@ -28,22 +49,10 @@
}
}
/* Image details page styles */
.image-overview-block img
@media only screen and (max-width: 500px)
{
max-height: 50vh;
max-width: 100%;
float: left;
cursor: zoom-in;
}
.image-overview-block div
{
display: inline-block;
margin-left: 20px;
}
.image-overview-block h1
{
margin-bottom: 0px;
.image-overview-block img
{
max-height: unset;
}
}
+2 -1
View File
@@ -4,7 +4,8 @@ header
display: grid;
grid-template-columns: 1fr auto;
grid-column-gap: 20px;
margin: 20px 50px;
margin-top: 20px;
margin-bottom: 20px;
}
h1
File diff suppressed because it is too large Load Diff
+61 -46
View File
@@ -2,21 +2,6 @@
This file contains main layout styles which applies to every View. In some views this rules are overrided in separate CSS files
*/
/* Declaring fonts */
@font-face
{
font-family: 'Consolas';
src: url("/fonts/Consolas/consolas.eot");
src: url("/fonts/Consolas/consolas.eot?#iefix") format("embedded-opentype"), url("/fonts/Consolas/consolas.otf") format("opentype"), url("/fonts/Consolas/consolas.svg") format("svg"), url("/fonts/Consolas/consolas.ttf") format("truetype"), url("/fonts/Consolas/consolas.woff") format("woff"), url("/fonts/Consolas/consolas.woff2") format("woff2");
}
@font-face
{
font-family: 'Segoe MDL2 Assets';
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot");
src: url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.eot?#iefix") format("embedded-opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.otf") format("opentype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.svg") format("svg"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.ttf") format("truetype"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff") format("woff"), url("/fonts/Segoe MDL2 Assets/segoeMLD2assets.woff2") format("woff2");
}
/* Header styles */
nav
{
@@ -33,6 +18,7 @@ nav
padding: 10px;
min-height: 33px;
font-size: 26px;
user-select: none;
}
nav a
@@ -66,30 +52,6 @@ menu
margin-top: 10px;
}
/* Adaptive code */
@media only screen and (min-width: 1000px)
{
menu
{
display: initial !important;
grid-row: 1;
grid-column: 2;
margin: 0px;
}
menu li
{
display: inline-block;
margin-right: 10px;
margin-top: 0px;
}
#menu-toggle
{
display: none;
}
}
/* Footer styles */
footer
{
@@ -123,7 +85,7 @@ body
overflow: auto;
margin: 0px;
margin-top: 53px;
font-family: 'Consolas', 'Segoe MDL2 Assets';
font-family: 'Consolas', 'SegoeMDL2Assets';
/* This stuff is necessary for sticky footer */
display: grid;
grid-template-rows: 1fr auto;
@@ -136,12 +98,12 @@ header a
color: black;
}
header a:hover
{
text-decoration: underline;
}
a:link:hover
{
text-decoration: underline;
}
article, header
article
{
margin: 0px 50px;
}
@@ -151,7 +113,60 @@ article, header
color: blue;
}
header
{
margin: 16px 50px;
}
.comment, .comment:visited
{
color: #57a64a !important;
}
text-decoration: none;
}
*[hidden]
{
display: none;
}
/* Adaptive code */
@media only screen and (min-width: 980px)
{
menu
{
display: initial !important;
grid-row: 1;
grid-column: 2;
margin: 0px;
}
menu li
{
display: inline-block;
margin-right: 10px;
margin-top: 0px;
}
#menu-toggle
{
display: none;
}
}
@media only screen and (max-width: 500px)
{
article
{
margin: 0px 20px;
}
header
{
margin: 16px 20px;
}
}
nav > div > a:nth-last-child(2)
{
visibility: hidden;
}
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 5.8 MiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 6.0 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 315 KiB

@@ -0,0 +1,41 @@
function Up(btn)
{
var item = btn.parentNode.parentNode;
var table = document.querySelector("tbody");
table.insertBefore(item, item.previousElementSibling);
document.querySelector("button").disabled = false;
}
function Down(btn)
{
var item = btn.parentNode.parentNode;
var table = document.querySelector("tbody");
table.insertBefore(item, item.nextElementSibling.nextElementSibling);
document.querySelector("button").disabled = false;
}
function ApplyReorder()
{
var table = document.querySelector("tbody");
var form = document.createElement("form");
form.method = "post";
form.hidden = true;
document.body.appendChild(form);
for (var k = 0; k < table.children.length; k++)
{
var item = document.createElement("input");
item.type = "text";
item.name = "reorderList";
item.value = table.children[k].id;
form.appendChild(item);
}
form.submit();
}