mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
- Added ability to edit paste.
- Added session cacheing of paste password.
This commit is contained in:
parent
063854f776
commit
a4365b2671
@ -1,4 +1,6 @@
|
||||
namespace Teknik.Areas.API.V1.Models
|
||||
using Teknik.Utilities;
|
||||
|
||||
namespace Teknik.Areas.API.V1.Models
|
||||
{
|
||||
public class PasteAPIv1Model : BaseAPIv1Model
|
||||
{
|
||||
@ -8,7 +10,7 @@
|
||||
|
||||
public string syntax { get; set; }
|
||||
|
||||
public string expireUnit { get; set; }
|
||||
public ExpirationUnit expireUnit { get; set; }
|
||||
|
||||
public int expireLength { get; set; }
|
||||
|
||||
@ -19,7 +21,7 @@
|
||||
code = null;
|
||||
title = string.Empty;
|
||||
syntax = "text";
|
||||
expireUnit = "never";
|
||||
expireUnit = ExpirationUnit.Never;
|
||||
expireLength = 1;
|
||||
password = string.Empty;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Teknik.Logging;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Diagnostics;
|
||||
|
||||
namespace Teknik.Areas.Paste.Controllers
|
||||
{
|
||||
@ -64,6 +65,7 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
model.Title = paste.Title;
|
||||
model.Syntax = paste.Syntax;
|
||||
model.DatePosted = paste.DatePosted;
|
||||
model.Username = paste.User?.Username;
|
||||
|
||||
if (User.Identity.IsAuthenticated && type.ToLower() == "full")
|
||||
{
|
||||
@ -80,6 +82,11 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
// The paste has a password set
|
||||
if (!string.IsNullOrEmpty(paste.HashedPassword))
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
// Try to get the password from the session
|
||||
password = GetCachedPassword(url);
|
||||
}
|
||||
string hash = string.Empty;
|
||||
if (!string.IsNullOrEmpty(password))
|
||||
{
|
||||
@ -89,6 +96,7 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
if (string.IsNullOrEmpty(password) || hash != paste.HashedPassword)
|
||||
{
|
||||
PasswordViewModel passModel = new PasswordViewModel();
|
||||
passModel.ActionUrl = Url.SubRouteUrl("p", "Paste.View");
|
||||
passModel.Url = url;
|
||||
passModel.Type = type;
|
||||
|
||||
@ -103,6 +111,9 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
// Save the password to the cache
|
||||
CachePassword(url, password);
|
||||
|
||||
// Read in the file
|
||||
string subDir = paste.FileName[0].ToString();
|
||||
string filePath = Path.Combine(_config.PasteConfig.PasteDirectory, subDir, paste.FileName);
|
||||
@ -158,7 +169,7 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
{
|
||||
Models.Paste paste = PasteHelper.CreatePaste(_config, _dbContext, model.Content, model.Title, model.Syntax, model.ExpireUnit, model.ExpireLength ?? 1, model.Password);
|
||||
|
||||
if (model.ExpireUnit == "view")
|
||||
if (model.ExpireUnit == ExpirationUnit.Views)
|
||||
{
|
||||
paste.Views = -1;
|
||||
}
|
||||
@ -175,6 +186,9 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
_dbContext.Pastes.Add(paste);
|
||||
_dbContext.SaveChanges();
|
||||
|
||||
// Cache the password
|
||||
CachePassword(paste.Url, model.Password);
|
||||
|
||||
return Redirect(Url.SubRouteUrl("p", "Paste.View", new { type = "Full", url = paste.Url }));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -186,6 +200,171 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
}
|
||||
return View("~/Areas/Paste/Views/Paste/Index.cshtml", model);
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Edit(string url, string password)
|
||||
{
|
||||
Models.Paste paste = _dbContext.Pastes.Where(p => p.Url == url).FirstOrDefault();
|
||||
if (paste != null)
|
||||
{
|
||||
if (paste.User?.Username != User.Identity.Name)
|
||||
return new StatusCodeResult(StatusCodes.Status403Forbidden);
|
||||
|
||||
ViewBag.Title = "Edit Paste";
|
||||
ViewBag.Description = "Edit your paste's content.";
|
||||
|
||||
// Check Expiration
|
||||
if (PasteHelper.CheckExpiration(paste))
|
||||
{
|
||||
_dbContext.Pastes.Remove(paste);
|
||||
_dbContext.SaveChanges();
|
||||
return new StatusCodeResult(StatusCodes.Status404NotFound);
|
||||
}
|
||||
|
||||
PasteViewModel model = new PasteViewModel();
|
||||
model.Url = url;
|
||||
model.Title = paste.Title;
|
||||
model.Syntax = paste.Syntax;
|
||||
model.DatePosted = paste.DatePosted;
|
||||
model.Username = paste.User?.Username;
|
||||
|
||||
byte[] ivBytes = Encoding.Unicode.GetBytes(paste.IV);
|
||||
byte[] keyBytes = AesCounterManaged.CreateKey(paste.Key, ivBytes, paste.KeySize);
|
||||
|
||||
// The paste has a password set
|
||||
if (!string.IsNullOrEmpty(paste.HashedPassword))
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
// Try to get the password from the session
|
||||
password = GetCachedPassword(url);
|
||||
}
|
||||
string hash = string.Empty;
|
||||
if (!string.IsNullOrEmpty(password))
|
||||
{
|
||||
hash = PasteHelper.HashPassword(paste.Key, password);
|
||||
keyBytes = AesCounterManaged.CreateKey(password, ivBytes, paste.KeySize);
|
||||
}
|
||||
if (string.IsNullOrEmpty(password) || hash != paste.HashedPassword)
|
||||
{
|
||||
PasswordViewModel passModel = new PasswordViewModel();
|
||||
passModel.ActionUrl = Url.SubRouteUrl("p", "Paste.Edit");
|
||||
passModel.Url = url;
|
||||
|
||||
if (!string.IsNullOrEmpty(password) && hash != paste.HashedPassword)
|
||||
{
|
||||
passModel.Error = true;
|
||||
passModel.ErrorMessage = "Invalid Password";
|
||||
}
|
||||
|
||||
// Redirect them to the password request page
|
||||
return View("~/Areas/Paste/Views/Paste/PasswordNeeded.cshtml", passModel);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the password
|
||||
CachePassword(url, password);
|
||||
|
||||
// Read in the file
|
||||
string subDir = paste.FileName[0].ToString();
|
||||
string filePath = Path.Combine(_config.PasteConfig.PasteDirectory, subDir, paste.FileName);
|
||||
if (!System.IO.File.Exists(filePath))
|
||||
{
|
||||
return new StatusCodeResult(StatusCodes.Status404NotFound);
|
||||
}
|
||||
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
using (AesCounterStream cs = new AesCounterStream(fs, false, keyBytes, ivBytes))
|
||||
using (StreamReader sr = new StreamReader(cs, Encoding.Unicode))
|
||||
{
|
||||
model.Content = await sr.ReadToEndAsync();
|
||||
}
|
||||
|
||||
return View("~/Areas/Paste/Views/Paste/Edit.cshtml", model);
|
||||
}
|
||||
return new StatusCodeResult(StatusCodes.Status404NotFound);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[DisableRequestSizeLimit]
|
||||
public IActionResult EditSubmit([Bind("Content, Title, Syntax, Url")]PasteEditViewModel model)
|
||||
{
|
||||
if (_config.PasteConfig.Enabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
Models.Paste paste = _dbContext.Pastes.Where(p => p.Url == model.Url).FirstOrDefault();
|
||||
if (paste != null)
|
||||
{
|
||||
if (paste.User?.Username != User.Identity.Name)
|
||||
return new StatusCodeResult(StatusCodes.Status403Forbidden);
|
||||
|
||||
string password = null;
|
||||
// The paste has a password set
|
||||
if (!string.IsNullOrEmpty(paste.HashedPassword))
|
||||
{
|
||||
// Try to get the password from the session
|
||||
password = GetCachedPassword(model.Url);
|
||||
string hash = string.Empty;
|
||||
if (!string.IsNullOrEmpty(password))
|
||||
{
|
||||
hash = PasteHelper.HashPassword(paste.Key, password);
|
||||
}
|
||||
if (string.IsNullOrEmpty(password) || hash != paste.HashedPassword)
|
||||
{
|
||||
PasswordViewModel passModel = new PasswordViewModel();
|
||||
passModel.ActionUrl = Url.SubRouteUrl("p", "Paste.Edit");
|
||||
passModel.Url = model.Url;
|
||||
|
||||
if (!string.IsNullOrEmpty(password) && hash != paste.HashedPassword)
|
||||
{
|
||||
passModel.Error = true;
|
||||
passModel.ErrorMessage = "Invalid Password";
|
||||
}
|
||||
|
||||
// Redirect them to the password request page
|
||||
return View("~/Areas/Paste/Views/Paste/PasswordNeeded.cshtml", passModel);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the old file
|
||||
string subDir = paste.FileName[0].ToString();
|
||||
string filePath = Path.Combine(_config.PasteConfig.PasteDirectory, subDir, paste.FileName);
|
||||
if (System.IO.File.Exists(filePath))
|
||||
System.IO.File.Delete(filePath);
|
||||
|
||||
// Generate a unique file name that does not currently exist
|
||||
string newFilePath = FileHelper.GenerateRandomFileName(_config.PasteConfig.PasteDirectory, _config.PasteConfig.FileExtension, 10);
|
||||
string fileName = Path.GetFileName(newFilePath);
|
||||
|
||||
string key = PasteHelper.GenerateKey(_config.PasteConfig.KeySize);
|
||||
string iv = PasteHelper.GenerateIV(_config.PasteConfig.BlockSize);
|
||||
|
||||
PasteHelper.EncryptContents(model.Content, newFilePath, password, key, iv, _config.PasteConfig.KeySize, _config.PasteConfig.ChunkSize);
|
||||
|
||||
paste.Key = key;
|
||||
paste.KeySize = _config.PasteConfig.KeySize;
|
||||
paste.IV = iv;
|
||||
paste.BlockSize = _config.PasteConfig.BlockSize;
|
||||
|
||||
paste.HashedPassword = PasteHelper.HashPassword(paste.Key, password);
|
||||
paste.FileName = fileName;
|
||||
paste.Title = model.Title;
|
||||
paste.Syntax = model.Syntax;
|
||||
paste.DateEdited = DateTime.Now;
|
||||
|
||||
_dbContext.Entry(paste).State = EntityState.Modified;
|
||||
_dbContext.SaveChanges();
|
||||
|
||||
return Redirect(Url.SubRouteUrl("p", "Paste.View", new { type = "Full", url = paste.Url }));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Redirect(Url.SubRouteUrl("error", "Error.500", new { exception = ex }));
|
||||
}
|
||||
}
|
||||
return new StatusCodeResult(StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public IActionResult Delete(string id)
|
||||
@ -206,11 +385,36 @@ namespace Teknik.Areas.Paste.Controllers
|
||||
System.IO.File.Delete(filePath);
|
||||
}
|
||||
|
||||
return Json(new { result = true });
|
||||
return Json(new { result = true, redirect = Url.SubRouteUrl("p", "Paste.Index") });
|
||||
}
|
||||
return Json(new { error = new { message = "You do not have permission to edit this Paste" } });
|
||||
}
|
||||
return Json(new { error = new { message = "This Paste does not exist" } });
|
||||
}
|
||||
|
||||
private void CachePassword(string url, string password)
|
||||
{
|
||||
if (HttpContext != null)
|
||||
{
|
||||
HttpContext.Session.Set("PastePassword_" + url, password);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetCachedPassword(string url)
|
||||
{
|
||||
if (HttpContext != null)
|
||||
{
|
||||
return HttpContext.Session.Get<string>("PastePassword_" + url);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ClearCachedPassword(string url)
|
||||
{
|
||||
if (HttpContext != null)
|
||||
{
|
||||
HttpContext.Session.Remove("PastePassword_" + url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,8 @@ namespace Teknik.Areas.Paste.Models
|
||||
|
||||
public DateTime DatePosted { get; set; }
|
||||
|
||||
public DateTime DateEdited { get; set; }
|
||||
|
||||
[CaseSensitive]
|
||||
public string Url { get; set; }
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace Teknik.Areas.Paste
|
||||
{
|
||||
public static class PasteHelper
|
||||
{
|
||||
public static Models.Paste CreatePaste(Config config, TeknikEntities db, string content, string title = "", string syntax = "text", string expireUnit = "never", int expireLength = 1, string password = "")
|
||||
public static Models.Paste CreatePaste(Config config, TeknikEntities db, string content, string title = "", string syntax = "text", ExpirationUnit expireUnit = ExpirationUnit.Never, int expireLength = 1, string password = "")
|
||||
{
|
||||
Models.Paste paste = new Models.Paste();
|
||||
paste.DatePosted = DateTime.Now;
|
||||
@ -30,26 +30,26 @@ namespace Teknik.Areas.Paste
|
||||
paste.Url = url;
|
||||
|
||||
// Figure out the expire date (null if 'never' or 'visit')
|
||||
switch (expireUnit.ToLower())
|
||||
switch (expireUnit)
|
||||
{
|
||||
case "never":
|
||||
case ExpirationUnit.Never:
|
||||
break;
|
||||
case "view":
|
||||
case ExpirationUnit.Views:
|
||||
paste.MaxViews = expireLength;
|
||||
break;
|
||||
case "minute":
|
||||
case ExpirationUnit.Minutes:
|
||||
paste.ExpireDate = paste.DatePosted.AddMinutes(expireLength);
|
||||
break;
|
||||
case "hour":
|
||||
case ExpirationUnit.Hours:
|
||||
paste.ExpireDate = paste.DatePosted.AddHours(expireLength);
|
||||
break;
|
||||
case "day":
|
||||
case ExpirationUnit.Days:
|
||||
paste.ExpireDate = paste.DatePosted.AddDays(expireLength);
|
||||
break;
|
||||
case "month":
|
||||
case ExpirationUnit.Months:
|
||||
paste.ExpireDate = paste.DatePosted.AddMonths(expireLength);
|
||||
break;
|
||||
case "year":
|
||||
case ExpirationUnit.Years:
|
||||
paste.ExpireDate = paste.DatePosted.AddYears(expireLength);
|
||||
break;
|
||||
default:
|
||||
|
@ -9,6 +9,8 @@ namespace Teknik.Areas.Paste.ViewModels
|
||||
{
|
||||
public class PasswordViewModel : ViewModelBase
|
||||
{
|
||||
public string ActionUrl { get; set; }
|
||||
|
||||
public string Url { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Teknik.Utilities;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Paste.ViewModels
|
||||
@ -15,7 +16,7 @@ namespace Teknik.Areas.Paste.ViewModels
|
||||
[Range(1, int.MaxValue)]
|
||||
public int? ExpireLength { get; set; }
|
||||
|
||||
public string ExpireUnit { get; set; }
|
||||
public ExpirationUnit ExpireUnit { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
|
||||
|
16
Teknik/Areas/Paste/ViewModels/PasteEditViewModel.cs
Normal file
16
Teknik/Areas/Paste/ViewModels/PasteEditViewModel.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Teknik.ViewModels;
|
||||
|
||||
namespace Teknik.Areas.Paste.ViewModels
|
||||
{
|
||||
public class PasteEditViewModel : ViewModelBase
|
||||
{
|
||||
public string Url { get; set; }
|
||||
|
||||
public string Content { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string Syntax { get; set; }
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ namespace Teknik.Areas.Paste.ViewModels
|
||||
public string Password { get; set; }
|
||||
public bool Hide { get; set; }
|
||||
public DateTime DatePosted { get; set; }
|
||||
public string Username { get; set; }
|
||||
|
||||
public List<Vault.Models.Vault> Vaults { get; set; }
|
||||
}
|
||||
|
48
Teknik/Areas/Paste/Views/Paste/Edit.cshtml
Normal file
48
Teknik/Areas/Paste/Views/Paste/Edit.cshtml
Normal file
@ -0,0 +1,48 @@
|
||||
@model Teknik.Areas.Paste.ViewModels.PasteViewModel
|
||||
|
||||
<bundle src="css/paste.edit.min.css" append-version="true"></bundle>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-offset-1 text-center">
|
||||
<b>@Html.ValidationSummary(true, "The input is not valid")</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-12">
|
||||
<!form class="form-horizontal" name="editor" method="post" action="@Url.SubRouteUrl("p", "Paste.Action", new { action = "EditSubmit", url = Model.Url })">
|
||||
<input type="hidden" class="form-control" name="Url" id="url" value="@Model.Url">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-10 col-sm-offset-1">
|
||||
<textarea class="form-control" name="Content" id="content" rows="20">@Model.Content</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="title" class="col-sm-2 col-sm-offset-1 control-label">Title</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="text" class="form-control" name="Title" id="title" value="@Model.Title">
|
||||
</div>
|
||||
<div class="col-sm-1 col-sm-offset-2">
|
||||
<button type="submit" class="btn btn-primary pull-right" id="pasteSubmit">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="syntax" class="col-sm-2 col-sm-offset-1 control-label">Syntax</label>
|
||||
<div class="col-sm-4">
|
||||
<select class="form-control" name="Syntax" id="syntax">
|
||||
<!option value=""@((string.IsNullOrEmpty(Model.Syntax)) ? " selected" : string.Empty)>Text</!option>
|
||||
|
||||
@foreach (var format in HighlightHelper.Languages.GroupBy(l => l.Value).ToList())
|
||||
{
|
||||
<!option value="@(format?.FirstOrDefault().Key)"@((Model.Syntax == format?.FirstOrDefault().Key) ? " selected" : string.Empty)>@(format?.Key)</!option>
|
||||
}
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</!form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<bundle src="js/paste.edit.min.js" append-version="true"></bundle>
|
@ -16,6 +16,7 @@
|
||||
|
||||
<script>
|
||||
var createVaultURL = '@Url.SubRouteUrl("vault", "Vault.NewVaultFromService", new { type = "Paste" })';
|
||||
var deletePasteURL = '@Url.SubRouteUrl("p", "Paste.Delete")';
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
@ -27,21 +28,35 @@
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-sm-12 pull-left">
|
||||
<div class="btn-group" role="group">
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Simple", new { url = Model.Url })">Simple</a>
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Raw", new { url = Model.Url })">Raw</a>
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Download", new { url = Model.Url })">Download</a>
|
||||
<button type="button" class="btn btn-default" id="create-vault" data-paste-url="@Model.Url" data-paste-title="@((string.IsNullOrEmpty(Model.Title)) ? "Untitled" : Model.Title)">Create Vault</button>
|
||||
@if (User.Identity.IsAuthenticated && Model.Vaults != null && Model.Vaults.Any())
|
||||
<div class="btn-toolbar" role="toolbar">
|
||||
<div class="btn-group" role="group">
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Simple", new { url = Model.Url })">Simple</a>
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Raw", new { url = Model.Url })">Raw</a>
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Download", new { url = Model.Url })">Download</a>
|
||||
</div>
|
||||
@if (User.Identity.IsAuthenticated && User.Identity.Name == Model.Username)
|
||||
{
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Add to Vault <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu pull-right" id="add-to-vault-menu">
|
||||
@foreach (Vault item in Model.Vaults)
|
||||
{
|
||||
<li><a href="#" class="add-to-vault" data-add-to-vault-url="@Url.SubRouteUrl("vault", "Vault.EditVault", new { url = item.Url, type = "Paste" })" data-paste-url="@Model.Url" data-paste-title="@((string.IsNullOrEmpty(Model.Title)) ? "Untitled" : Model.Title)">@item.Title</a></li>
|
||||
}
|
||||
</ul>
|
||||
<div class="btn-group pull-right" role="group">
|
||||
<a role="button" class="btn btn-default" href="@Url.SubRouteUrl("p", "Paste.Edit", new { url = Model.Url })"><span class="text-primary">Edit</span></a>
|
||||
<button type="button" class="btn btn-default" id="delete-paste" data-paste-url="@Model.Url"><span class="text-danger">Delete</span></button>
|
||||
</div>
|
||||
}
|
||||
<div class="btn-group pull-right" role="group">
|
||||
<button type="button" class="btn btn-default" id="create-vault" data-paste-url="@Model.Url" data-paste-title="@((string.IsNullOrEmpty(Model.Title)) ? "Untitled" : Model.Title)">Create Vault</button>
|
||||
@if (User.Identity.IsAuthenticated)
|
||||
{
|
||||
@if (Model.Vaults != null && Model.Vaults.Any())
|
||||
{
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Add to Vault <span class="caret"></span></button>
|
||||
<ul class="dropdown-menu pull-right" id="add-to-vault-menu">
|
||||
@foreach (Vault item in Model.Vaults)
|
||||
{
|
||||
<li><a href="#" class="add-to-vault" data-add-to-vault-url="@Url.SubRouteUrl("vault", "Vault.EditVault", new { url = item.Url, type = "Paste" })" data-paste-url="@Model.Url" data-paste-title="@((string.IsNullOrEmpty(Model.Title)) ? "Untitled" : Model.Title)">@item.Title</a></li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,13 +46,10 @@
|
||||
</div>
|
||||
<div class="col-sm-4" id="unit-div">
|
||||
<select class="form-control" name="ExpireUnit" id="expireunit">
|
||||
<!option value="never">Never</!option>
|
||||
<!option value="view">Views</!option>
|
||||
<!option value="minute">Minutes</!option>
|
||||
<!option value="hour">Hours</!option>
|
||||
<!option value="day">Days</!option>
|
||||
<!option value="month">Months</!option>
|
||||
<!option value="year">Years</!option>
|
||||
@foreach (ExpirationUnit unit in Enum.GetValues(typeof(ExpirationUnit)))
|
||||
{
|
||||
<!option value="@unit">@unit.ToString()</!option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
<div class="row text-center">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<!form class="form-inline" method="post" action="@Url.SubRouteUrl("paste", "Paste.View")">
|
||||
<!form class="form-inline" method="post" action="@Model.ActionUrl">
|
||||
<h3>This paste is password protected</h3>
|
||||
<input type="hidden" name="type" value="@Model.Type">
|
||||
<input type="hidden" name="url" value="@Model.Url">
|
||||
|
29
Teknik/Content/Paste/EditPaste.css
Normal file
29
Teknik/Content/Paste/EditPaste.css
Normal file
@ -0,0 +1,29 @@
|
||||
pre {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
pre code,
|
||||
pre .line-number {
|
||||
/* Ukuran line-height antara teks di dalam tag <code> dan <span class="line-number"> harus sama! */
|
||||
font:normal normal 12px/14px "Courier New",Courier,Monospace;
|
||||
color:black;
|
||||
display:block;
|
||||
}
|
||||
|
||||
pre .line-number {
|
||||
float:left;
|
||||
margin:0 1em 0 -1em;
|
||||
padding-top: 5px;
|
||||
border-right:1px solid;
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
pre .line-number span {
|
||||
display:block;
|
||||
padding:0 .5em 0 1em;
|
||||
}
|
||||
|
||||
pre .cl {
|
||||
display:block;
|
||||
clear:both;
|
||||
}
|
749
Teknik/Data/Migrations/20190124080711_PasteEditDate.Designer.cs
generated
Normal file
749
Teknik/Data/Migrations/20190124080711_PasteEditDate.Designer.cs
generated
Normal file
@ -0,0 +1,749 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Teknik.Data;
|
||||
|
||||
namespace Teknik.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(TeknikEntities))]
|
||||
[Migration("20190124080711_PasteEditDate")]
|
||||
partial class PasteEditDate
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "2.2.0-preview3-35497")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.Blog", b =>
|
||||
{
|
||||
b.Property<int>("BlogId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<int>("UserId");
|
||||
|
||||
b.HasKey("BlogId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Blogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPost", b =>
|
||||
{
|
||||
b.Property<int>("BlogPostId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Article");
|
||||
|
||||
b.Property<int>("BlogId");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<DateTime>("DatePublished");
|
||||
|
||||
b.Property<bool>("Published");
|
||||
|
||||
b.Property<bool>("System");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("BlogPostId");
|
||||
|
||||
b.HasIndex("BlogId");
|
||||
|
||||
b.ToTable("BlogPosts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPostComment", b =>
|
||||
{
|
||||
b.Property<int>("BlogPostCommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Article");
|
||||
|
||||
b.Property<int>("BlogPostId");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("BlogPostCommentId");
|
||||
|
||||
b.HasIndex("BlogPostId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("BlogPostComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPostTag", b =>
|
||||
{
|
||||
b.Property<int>("BlogPostTagId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<int>("BlogPostId");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.HasKey("BlogPostTagId");
|
||||
|
||||
b.HasIndex("BlogPostId");
|
||||
|
||||
b.ToTable("BlogPostTags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Contact.Models.Contact", b =>
|
||||
{
|
||||
b.Property<int>("ContactId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("DateAdded");
|
||||
|
||||
b.Property<string>("Email");
|
||||
|
||||
b.Property<string>("Message");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<string>("Subject");
|
||||
|
||||
b.HasKey("ContactId");
|
||||
|
||||
b.ToTable("Contact");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Paste.Models.Paste", b =>
|
||||
{
|
||||
b.Property<int>("PasteId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<int>("BlockSize");
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<string>("DeleteKey")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<DateTime?>("ExpireDate");
|
||||
|
||||
b.Property<string>("FileName")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<string>("HashedPassword")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<string>("IV")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<string>("Key")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int>("KeySize");
|
||||
|
||||
b.Property<int>("MaxViews");
|
||||
|
||||
b.Property<string>("Syntax");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.Property<int>("Views");
|
||||
|
||||
b.HasKey("PasteId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Pastes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.Podcast", b =>
|
||||
{
|
||||
b.Property<int>("PodcastId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<DateTime>("DatePublished");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<int>("Episode");
|
||||
|
||||
b.Property<bool>("Published");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.HasKey("PodcastId");
|
||||
|
||||
b.ToTable("Podcasts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastComment", b =>
|
||||
{
|
||||
b.Property<int>("PodcastCommentId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Article");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<int>("UserId");
|
||||
|
||||
b.HasKey("PodcastCommentId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("PodcastComments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastFile", b =>
|
||||
{
|
||||
b.Property<int>("PodcastFileId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<long>("ContentLength");
|
||||
|
||||
b.Property<string>("ContentType");
|
||||
|
||||
b.Property<string>("FileName");
|
||||
|
||||
b.Property<string>("Path");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.Property<int>("Size");
|
||||
|
||||
b.HasKey("PodcastFileId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastFiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastTag", b =>
|
||||
{
|
||||
b.Property<int>("PodcastTagId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Name");
|
||||
|
||||
b.Property<int>("PodcastId");
|
||||
|
||||
b.HasKey("PodcastTagId");
|
||||
|
||||
b.HasIndex("PodcastId");
|
||||
|
||||
b.ToTable("PodcastTags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Shortener.Models.ShortenedUrl", b =>
|
||||
{
|
||||
b.Property<int>("ShortenedUrlId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("DateAdded");
|
||||
|
||||
b.Property<string>("OriginalUrl");
|
||||
|
||||
b.Property<string>("ShortUrl")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.Property<int>("Views");
|
||||
|
||||
b.HasKey("ShortenedUrlId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("ShortenedUrls");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Stats.Models.Takedown", b =>
|
||||
{
|
||||
b.Property<int>("TakedownId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("ActionTaken");
|
||||
|
||||
b.Property<DateTime>("DateActionTaken");
|
||||
|
||||
b.Property<DateTime>("DateRequested");
|
||||
|
||||
b.Property<string>("Reason");
|
||||
|
||||
b.Property<string>("Requester");
|
||||
|
||||
b.Property<string>("RequesterContact");
|
||||
|
||||
b.HasKey("TakedownId");
|
||||
|
||||
b.ToTable("Takedowns");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Stats.Models.Transaction", b =>
|
||||
{
|
||||
b.Property<int>("TransactionId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("decimal(19, 5)");
|
||||
|
||||
b.Property<int>("Currency");
|
||||
|
||||
b.Property<DateTime>("DateSent");
|
||||
|
||||
b.Property<string>("Reason");
|
||||
|
||||
b.HasKey("TransactionId");
|
||||
|
||||
b.ToTable("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Upload.Models.Upload", b =>
|
||||
{
|
||||
b.Property<int>("UploadId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<int>("BlockSize");
|
||||
|
||||
b.Property<long>("ContentLength");
|
||||
|
||||
b.Property<string>("ContentType");
|
||||
|
||||
b.Property<DateTime>("DateUploaded");
|
||||
|
||||
b.Property<string>("DeleteKey")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int>("Downloads");
|
||||
|
||||
b.Property<DateTime?>("ExpireDate");
|
||||
|
||||
b.Property<string>("FileName")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<string>("IV")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<string>("Key")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int>("KeySize");
|
||||
|
||||
b.Property<int>("MaxDownloads");
|
||||
|
||||
b.Property<int?>("Takedown_TakedownId");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.HasKey("UploadId");
|
||||
|
||||
b.HasIndex("Takedown_TakedownId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Uploads");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.InviteCode", b =>
|
||||
{
|
||||
b.Property<int>("InviteCodeId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<bool>("Active");
|
||||
|
||||
b.Property<int?>("ClaimedUserId");
|
||||
|
||||
b.Property<string>("Code")
|
||||
.HasAnnotation("CaseSensitive", true);
|
||||
|
||||
b.Property<int?>("OwnerId");
|
||||
|
||||
b.HasKey("InviteCodeId");
|
||||
|
||||
b.HasIndex("ClaimedUserId")
|
||||
.IsUnique()
|
||||
.HasFilter("[ClaimedUserId] IS NOT NULL");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("InviteCodes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.LoginInfo", b =>
|
||||
{
|
||||
b.Property<int>("LoginInfoId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("LoginProvider");
|
||||
|
||||
b.Property<string>("ProviderDisplayName");
|
||||
|
||||
b.Property<string>("ProviderKey");
|
||||
|
||||
b.Property<int>("UserId");
|
||||
|
||||
b.HasKey("LoginInfoId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserLogins");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<string>("Username");
|
||||
|
||||
b.HasKey("UserId");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.Vault", b =>
|
||||
{
|
||||
b.Property<int>("VaultId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("DateCreated");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<string>("Url");
|
||||
|
||||
b.Property<int?>("UserId");
|
||||
|
||||
b.Property<int>("Views");
|
||||
|
||||
b.HasKey("VaultId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Vaults");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.VaultItem", b =>
|
||||
{
|
||||
b.Property<int>("VaultItemId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b.Property<DateTime>("DateAdded");
|
||||
|
||||
b.Property<string>("Description");
|
||||
|
||||
b.Property<string>("Discriminator")
|
||||
.IsRequired();
|
||||
|
||||
b.Property<string>("Title");
|
||||
|
||||
b.Property<int>("VaultId");
|
||||
|
||||
b.HasKey("VaultItemId");
|
||||
|
||||
b.HasIndex("VaultId");
|
||||
|
||||
b.ToTable("VaultItems");
|
||||
|
||||
b.HasDiscriminator<string>("Discriminator").HasValue("VaultItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.PasteVaultItem", b =>
|
||||
{
|
||||
b.HasBaseType("Teknik.Areas.Vault.Models.VaultItem");
|
||||
|
||||
b.Property<int>("PasteId");
|
||||
|
||||
b.HasIndex("PasteId");
|
||||
|
||||
b.HasDiscriminator().HasValue("PasteVaultItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.UploadVaultItem", b =>
|
||||
{
|
||||
b.HasBaseType("Teknik.Areas.Vault.Models.VaultItem");
|
||||
|
||||
b.Property<int>("UploadId");
|
||||
|
||||
b.HasIndex("UploadId");
|
||||
|
||||
b.HasDiscriminator().HasValue("UploadVaultItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.Blog", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPost", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Blog.Models.Blog", "Blog")
|
||||
.WithMany("BlogPosts")
|
||||
.HasForeignKey("BlogId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPostComment", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Blog.Models.BlogPost", "BlogPost")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("BlogPostId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Blog.Models.BlogPostTag", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Blog.Models.BlogPost", "BlogPost")
|
||||
.WithMany("Tags")
|
||||
.HasForeignKey("BlogPostId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Paste.Models.Paste", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany("Pastes")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastComment", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Podcast.Models.Podcast", "Podcast")
|
||||
.WithMany("Comments")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastFile", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Podcast.Models.Podcast", "Podcast")
|
||||
.WithMany("Files")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Podcast.Models.PodcastTag", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Podcast.Models.Podcast", "Podcast")
|
||||
.WithMany("Tags")
|
||||
.HasForeignKey("PodcastId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Shortener.Models.ShortenedUrl", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany("ShortenedUrls")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Upload.Models.Upload", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Stats.Models.Takedown")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("Takedown_TakedownId");
|
||||
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany("Uploads")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.InviteCode", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "ClaimedUser")
|
||||
.WithOne("ClaimedInviteCode")
|
||||
.HasForeignKey("Teknik.Areas.Users.Models.InviteCode", "ClaimedUserId");
|
||||
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "Owner")
|
||||
.WithMany("OwnedInviteCodes")
|
||||
.HasForeignKey("OwnerId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.LoginInfo", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Users.Models.User", b =>
|
||||
{
|
||||
b.OwnsOne("Teknik.Areas.Users.Models.BlogSettings", "BlogSettings", b1 =>
|
||||
{
|
||||
b1.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b1.Property<string>("Description")
|
||||
.HasColumnName("Description");
|
||||
|
||||
b1.Property<string>("Title")
|
||||
.HasColumnName("Title");
|
||||
|
||||
b1.HasKey("UserId");
|
||||
|
||||
b1.ToTable("Users");
|
||||
|
||||
b1.HasOne("Teknik.Areas.Users.Models.User")
|
||||
.WithOne("BlogSettings")
|
||||
.HasForeignKey("Teknik.Areas.Users.Models.BlogSettings", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
b.OwnsOne("Teknik.Areas.Users.Models.UploadSettings", "UploadSettings", b1 =>
|
||||
{
|
||||
b1.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b1.Property<bool>("Encrypt")
|
||||
.HasColumnName("Encrypt");
|
||||
|
||||
b1.Property<int>("ExpirationLength")
|
||||
.HasColumnName("ExpirationLength");
|
||||
|
||||
b1.Property<int>("ExpirationUnit")
|
||||
.HasColumnName("ExpirationUnit");
|
||||
|
||||
b1.HasKey("UserId");
|
||||
|
||||
b1.ToTable("Users");
|
||||
|
||||
b1.HasOne("Teknik.Areas.Users.Models.User")
|
||||
.WithOne("UploadSettings")
|
||||
.HasForeignKey("Teknik.Areas.Users.Models.UploadSettings", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
b.OwnsOne("Teknik.Areas.Users.Models.UserSettings", "UserSettings", b1 =>
|
||||
{
|
||||
b1.Property<int>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn);
|
||||
|
||||
b1.Property<string>("About")
|
||||
.HasColumnName("About");
|
||||
|
||||
b1.Property<string>("Quote")
|
||||
.HasColumnName("Quote");
|
||||
|
||||
b1.Property<string>("Website")
|
||||
.HasColumnName("Website");
|
||||
|
||||
b1.HasKey("UserId");
|
||||
|
||||
b1.ToTable("Users");
|
||||
|
||||
b1.HasOne("Teknik.Areas.Users.Models.User")
|
||||
.WithOne("UserSettings")
|
||||
.HasForeignKey("Teknik.Areas.Users.Models.UserSettings", "UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.Vault", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Users.Models.User", "User")
|
||||
.WithMany("Vaults")
|
||||
.HasForeignKey("UserId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.VaultItem", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Vault.Models.Vault", "Vault")
|
||||
.WithMany("VaultItems")
|
||||
.HasForeignKey("VaultId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.PasteVaultItem", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Paste.Models.Paste", "Paste")
|
||||
.WithMany("PasteVaultItems")
|
||||
.HasForeignKey("PasteId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Teknik.Areas.Vault.Models.UploadVaultItem", b =>
|
||||
{
|
||||
b.HasOne("Teknik.Areas.Upload.Models.Upload", "Upload")
|
||||
.WithMany("UploadVaultItems")
|
||||
.HasForeignKey("UploadId")
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
24
Teknik/Data/Migrations/20190124080711_PasteEditDate.cs
Normal file
24
Teknik/Data/Migrations/20190124080711_PasteEditDate.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Teknik.Data.Migrations
|
||||
{
|
||||
public partial class PasteEditDate : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "DateEdited",
|
||||
table: "Pastes",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "DateEdited",
|
||||
table: "Pastes");
|
||||
}
|
||||
}
|
||||
}
|
@ -138,6 +138,8 @@ namespace Teknik.Data.Migrations
|
||||
|
||||
b.Property<string>("Content");
|
||||
|
||||
b.Property<DateTime>("DateEdited");
|
||||
|
||||
b.Property<DateTime>("DatePosted");
|
||||
|
||||
b.Property<string>("DeleteKey")
|
||||
|
@ -417,6 +417,13 @@ namespace Teknik
|
||||
template: "Download/{url}/{password?}",
|
||||
defaults: new { area = "Paste", controller = "Paste", action = "ViewPaste", type = "Download" }
|
||||
);
|
||||
routes.MapSubdomainRoute(
|
||||
name: "Paste.Edit",
|
||||
domains: new List<string>() { config.Host },
|
||||
subDomains: new List<string>() { "paste", "p" },
|
||||
template: "Edit/{url}/{password?}",
|
||||
defaults: new { area = "Paste", controller = "Paste", action = "Edit" }
|
||||
);
|
||||
routes.MapSubdomainRoute(
|
||||
name: "Paste.Delete",
|
||||
domains: new List<string>() { config.Host },
|
||||
|
3
Teknik/Scripts/Paste/EditPaste.js
Normal file
3
Teknik/Scripts/Paste/EditPaste.js
Normal file
@ -0,0 +1,3 @@
|
||||
$(document).ready(function () {
|
||||
$('#content').focus();
|
||||
});
|
@ -1,10 +1,41 @@
|
||||
/* globals createVaultURL */
|
||||
/* globals createVaultURL, deletePasteURL */
|
||||
$(document).ready(function () {
|
||||
linkCreateVault($('#create-vault'));
|
||||
|
||||
$('#add-to-vault-menu').find('.add-to-vault').each(function () {
|
||||
linkAddToVault($(this));
|
||||
});
|
||||
|
||||
$('#delete-paste').click(function () {
|
||||
var id = $(this).data('paste-url');
|
||||
|
||||
bootbox.confirm("Are you sure you want to delete this paste?", function (result) {
|
||||
if (result) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: deletePasteURL,
|
||||
data: { id: id },
|
||||
headers: { 'X-Requested-With': 'XMLHttpRequest' },
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
success: function (response) {
|
||||
if (response.result) {
|
||||
window.location = response.redirect;
|
||||
}
|
||||
else {
|
||||
$("#top_msg").css('display', 'inline', 'important');
|
||||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(response) + '</div>');
|
||||
}
|
||||
},
|
||||
error: function (response) {
|
||||
$("#top_msg").css('display', 'inline', 'important');
|
||||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(response.responseText) + '</div>');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function linkCreateVault(element) {
|
||||
|
@ -96,6 +96,9 @@
|
||||
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Areas\Paste\Views\Paste\Edit.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
<Content Update="Areas\User\Views\User\Settings\ClientView.cshtml">
|
||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||
</Content>
|
||||
|
@ -99,6 +99,7 @@
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/paste.view.min.js",
|
||||
"inputFiles": [
|
||||
"./wwwroot/lib/bootbox/js/bootbox.js",
|
||||
"./wwwroot/js/app/lib/Prism/prism.js",
|
||||
"./wwwroot/js/app/lib/Prism/prism-line-numbers.js",
|
||||
"./wwwroot/js/app/lib/Prism/prism-line-highlight.js",
|
||||
@ -113,6 +114,24 @@
|
||||
"./wwwroot/css/app/lib/Prism/prism-vs.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/paste.edit.min.js",
|
||||
"inputFiles": [
|
||||
"./wwwroot/js/app/lib/Prism/prism.js",
|
||||
"./wwwroot/js/app/lib/Prism/prism-line-numbers.js",
|
||||
"./wwwroot/js/app/lib/Prism/prism-line-highlight.js",
|
||||
"./wwwroot/js/app/Paste/EditPaste.js"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/css/paste.edit.min.css",
|
||||
"inputFiles": [
|
||||
"./wwwroot/css/app/lib/Prism/prism-line-numbers.css",
|
||||
"./wwwroot/css/app/lib/Prism/prism-line-highlight.css",
|
||||
"./wwwroot/css/app/lib/Prism/prism-vs.css",
|
||||
"./wwwroot/css/app/Paste/EditPaste.css"
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputFileName": "./wwwroot/js/podcast.min.js",
|
||||
"inputFiles": [
|
||||
|
Loading…
Reference in New Issue
Block a user