- Reorganized settings pages into individual pages.tags/3.0.0
@@ -132,5 +132,24 @@ namespace Teknik.Areas.Admin.Controllers | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http404")); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult CreateInviteCode(string username) | |||
{ | |||
if (UserHelper.UserExists(db, username)) | |||
{ | |||
User user = UserHelper.GetUser(db, username); | |||
InviteCode inviteCode = db.InviteCodes.Create(); | |||
inviteCode.Active = true; | |||
inviteCode.Code = Guid.NewGuid().ToString(); | |||
inviteCode.Owner = user; | |||
db.InviteCodes.Add(inviteCode); | |||
db.SaveChanges(); | |||
return Json(new { result = new { code = inviteCode.Code } }); | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http404")); | |||
} | |||
} | |||
} |
@@ -9,15 +9,15 @@ $(function () { | |||
data: AddAntiForgeryToken({ username: username, accountType: selected }), | |||
success: function (html) { | |||
if (html) { | |||
if (html.error) { | |||
$("#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>' + html.error.message + '</div>'); | |||
} | |||
else { | |||
if (html.result.success) { | |||
$("#top_msg").css('display', 'none'); | |||
$("#top_msg").html(''); | |||
alert('Successfully changed the account type for \'' + username + '\' to type: ' + selected); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
} | |||
}); | |||
@@ -32,18 +32,36 @@ $(function () { | |||
data: AddAntiForgeryToken({ username: username, accountStatus: selected }), | |||
success: function (html) { | |||
if (html) { | |||
if (html.error) { | |||
$("#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>' + html.error.message + '</div>'); | |||
} | |||
else { | |||
if (html.result.success) { | |||
$("#top_msg").css('display', 'none'); | |||
$("#top_msg").html(''); | |||
alert('Successfully changed the account status for \'' + username + '\' to: ' + selected); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
} | |||
}); | |||
}); | |||
$('#createInviteCode').click(function () { | |||
$.ajax({ | |||
type: "POST", | |||
url: createInviteCode, | |||
data: AddAntiForgeryToken({ username: username }), | |||
success: function (html) { | |||
if (html.result) { | |||
$("#top_msg").css('display', 'none'); | |||
$("#top_msg").html(''); | |||
alert('Successfully created invite code for \'' + username + '\': ' + html.result.code); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
}); | |||
}); |
@@ -6,6 +6,7 @@ | |||
// We need to define the action URLs for the script | |||
var editAccountType = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountType" })'; | |||
var editAccountStatus = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "EditUserAccountStatus" })'; | |||
var createInviteCode = '@Url.SubRouteUrl("admin", "Admin.Action", new { action = "CreateInviteCode" })'; | |||
var username = '@Model.Username'; | |||
</script> | |||
@@ -52,4 +53,10 @@ | |||
</select> | |||
</div> | |||
</div> | |||
<br /> | |||
<div class="row"> | |||
<div class="col-sm-2 col-sm-offset-1"> | |||
<button type="button" class="list-group-item btn-info" id="createInviteCode">Create Invite Code</button> | |||
</div> | |||
</div> | |||
</div> |
@@ -102,23 +102,56 @@ namespace Teknik.Areas.Users.Controllers | |||
[TrackPageView] | |||
public ActionResult Settings() | |||
{ | |||
string username = User.Identity.Name; | |||
return Redirect(Url.SubRouteUrl("user", "User.SecuritySettings")); | |||
} | |||
SettingsViewModel model = new SettingsViewModel(); | |||
ViewBag.Title = "User Does Not Exist - " + Config.Title; | |||
ViewBag.Description = "The User does not exist"; | |||
[TrackPageView] | |||
public ActionResult ProfileSettings() | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
string username = User.Identity.Name; | |||
User user = UserHelper.GetUser(db, username); | |||
if (user != null) | |||
{ | |||
Session["AuthenticatedUser"] = user; | |||
ViewBag.Title = "Profile Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Profile Settings"; | |||
ProfileSettingsViewModel model = new ProfileSettingsViewModel(); | |||
model.Page = "Profile"; | |||
model.UserID = user.UserId; | |||
model.Username = user.Username; | |||
model.About = user.UserSettings.About; | |||
model.Quote = user.UserSettings.Quote; | |||
model.Website = user.UserSettings.Website; | |||
return View("/Areas/User/Views/User/Settings/ProfileSettings.cshtml", model); | |||
} | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http403")); | |||
} | |||
[TrackPageView] | |||
public ActionResult SecuritySettings() | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
string username = User.Identity.Name; | |||
User user = UserHelper.GetUser(db, username); | |||
if (user != null) | |||
{ | |||
Session["AuthenticatedUser"] = user; | |||
ViewBag.Title = "Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Settings"; | |||
ViewBag.Title = "Security Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Security Settings"; | |||
SecuritySettingsViewModel model = new SecuritySettingsViewModel(); | |||
model.Page = "Security"; | |||
model.UserID = user.UserId; | |||
model.Username = user.Username; | |||
model.TrustedDeviceCount = user.TrustedDevices.Count; | |||
@@ -133,16 +166,126 @@ namespace Teknik.Areas.Users.Controllers | |||
model.AuthTokens.Add(tokenModel); | |||
} | |||
model.UserSettings = user.UserSettings; | |||
model.SecuritySettings = user.SecuritySettings; | |||
model.BlogSettings = user.BlogSettings; | |||
model.UploadSettings = user.UploadSettings; | |||
model.PgpPublicKey = user.SecuritySettings.PGPSignature; | |||
model.RecoveryEmail = user.SecuritySettings.RecoveryEmail; | |||
model.RecoveryVerified = user.SecuritySettings.RecoveryVerified; | |||
model.AllowTrustedDevices = user.SecuritySettings.AllowTrustedDevices; | |||
model.TwoFactorEnabled = user.SecuritySettings.TwoFactorEnabled; | |||
model.TwoFactorKey = user.SecuritySettings.TwoFactorKey; | |||
return View(model); | |||
return View("/Areas/User/Views/User/Settings/SecuritySettings.cshtml", model); | |||
} | |||
} | |||
model.Error = true; | |||
return View(model); | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http403")); | |||
} | |||
[TrackPageView] | |||
public ActionResult InviteSettings() | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
string username = User.Identity.Name; | |||
User user = UserHelper.GetUser(db, username); | |||
if (user != null) | |||
{ | |||
Session["AuthenticatedUser"] = user; | |||
ViewBag.Title = "Invite Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Invite Settings"; | |||
InviteSettingsViewModel model = new InviteSettingsViewModel(); | |||
model.Page = "Invite"; | |||
model.UserID = user.UserId; | |||
model.Username = user.Username; | |||
List<InviteCodeViewModel> availableCodes = new List<InviteCodeViewModel>(); | |||
List<InviteCodeViewModel> claimedCodes = new List<InviteCodeViewModel>(); | |||
if (user.OwnedInviteCodes != null) | |||
{ | |||
foreach (InviteCode inviteCode in user.OwnedInviteCodes.Where(c => c.Active)) | |||
{ | |||
InviteCodeViewModel inviteCodeViewModel = new InviteCodeViewModel(); | |||
inviteCodeViewModel.ClaimedUser = inviteCode.ClaimedUser; | |||
inviteCodeViewModel.Active = inviteCode.Active; | |||
inviteCodeViewModel.Code = inviteCode.Code; | |||
inviteCodeViewModel.InviteCodeId = inviteCode.InviteCodeId; | |||
inviteCodeViewModel.Owner = inviteCode.Owner; | |||
if (inviteCode.ClaimedUser == null) | |||
availableCodes.Add(inviteCodeViewModel); | |||
if (inviteCode.ClaimedUser != null) | |||
claimedCodes.Add(inviteCodeViewModel); | |||
} | |||
} | |||
model.AvailableCodes = availableCodes; | |||
model.ClaimedCodes = claimedCodes; | |||
return View("/Areas/User/Views/User/Settings/InviteSettings.cshtml", model); | |||
} | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http403")); | |||
} | |||
[TrackPageView] | |||
public ActionResult BlogSettings() | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
string username = User.Identity.Name; | |||
User user = UserHelper.GetUser(db, username); | |||
if (user != null) | |||
{ | |||
Session["AuthenticatedUser"] = user; | |||
ViewBag.Title = "Blog Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Blog Settings"; | |||
BlogSettingsViewModel model = new BlogSettingsViewModel(); | |||
model.Page = "Blog"; | |||
model.UserID = user.UserId; | |||
model.Username = user.Username; | |||
model.Title = user.BlogSettings.Title; | |||
model.Description = user.BlogSettings.Description; | |||
return View("/Areas/User/Views/User/Settings/BlogSettings.cshtml", model); | |||
} | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http403")); | |||
} | |||
[TrackPageView] | |||
public ActionResult UploadSettings() | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
string username = User.Identity.Name; | |||
User user = UserHelper.GetUser(db, username); | |||
if (user != null) | |||
{ | |||
Session["AuthenticatedUser"] = user; | |||
ViewBag.Title = "Upload Settings - " + Config.Title; | |||
ViewBag.Description = "Your " + Config.Title + " Upload Settings"; | |||
UploadSettingsViewModel model = new UploadSettingsViewModel(); | |||
model.Page = "Upload"; | |||
model.UserID = user.UserId; | |||
model.Username = user.Username; | |||
model.Encrypt = user.UploadSettings.Encrypt; | |||
return View("/Areas/User/Views/User/Settings/UploadSettings.cshtml", model); | |||
} | |||
} | |||
return Redirect(Url.SubRouteUrl("error", "Error.Http403")); | |||
} | |||
[HttpGet] | |||
@@ -295,9 +438,10 @@ namespace Teknik.Areas.Users.Controllers | |||
[HttpGet] | |||
[TrackPageView] | |||
[AllowAnonymous] | |||
public ActionResult Register(string ReturnUrl) | |||
public ActionResult Register(string inviteCode, string ReturnUrl) | |||
{ | |||
RegisterViewModel model = new RegisterViewModel(); | |||
model.InviteCode = inviteCode; | |||
model.ReturnUrl = ReturnUrl; | |||
return View("/Areas/User/Views/User/ViewRegistration.cshtml", model); | |||
@@ -331,6 +475,18 @@ namespace Teknik.Areas.Users.Controllers | |||
model.ErrorMessage = "Passwords must match"; | |||
} | |||
// Validate the Invite Code | |||
if (!model.Error && Config.UserConfig.InviteCodeRequired && string.IsNullOrEmpty(model.InviteCode)) | |||
{ | |||
model.Error = true; | |||
model.ErrorMessage = "An Invite Code is required to register"; | |||
} | |||
if (!model.Error && !string.IsNullOrEmpty(model.InviteCode) && db.InviteCodes.Where(c => c.Code == model.InviteCode && c.Active && c.ClaimedUser == null).FirstOrDefault() == null) | |||
{ | |||
model.Error = true; | |||
model.ErrorMessage = "Invalid Invite Code"; | |||
} | |||
// PGP Key valid? | |||
if (!model.Error && !string.IsNullOrEmpty(model.PublicKey) && !PGP.IsPublicKey(model.PublicKey)) | |||
{ | |||
@@ -355,6 +511,16 @@ namespace Teknik.Areas.Users.Controllers | |||
if (!string.IsNullOrEmpty(model.RecoveryEmail)) | |||
newUser.SecuritySettings.RecoveryEmail = model.RecoveryEmail; | |||
// if they provided an invite code, let's assign them to it | |||
if (!string.IsNullOrEmpty(model.InviteCode)) | |||
{ | |||
InviteCode code = db.InviteCodes.Where(c => c.Code == model.InviteCode).FirstOrDefault(); | |||
db.Entry(code).State = EntityState.Modified; | |||
db.SaveChanges(); | |||
newUser.ClaimedInviteCode = code; | |||
} | |||
UserHelper.AddAccount(db, Config, newUser, model.Password); | |||
// If they have a recovery email, let's send a verification | |||
@@ -389,7 +555,70 @@ namespace Teknik.Areas.Users.Controllers | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult Edit(EditSettingsViewModel settings) | |||
public ActionResult EditBlog(BlogSettingsViewModel settings) | |||
{ | |||
if (ModelState.IsValid) | |||
{ | |||
try | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
User user = UserHelper.GetUser(db, User.Identity.Name); | |||
if (user != null) | |||
{ | |||
// Blogs | |||
user.BlogSettings.Title = settings.Title; | |||
user.BlogSettings.Description = settings.Description; | |||
UserHelper.EditAccount(db, Config, user); | |||
return Json(new { result = true }); | |||
} | |||
return Json(new { error = "User does not exist" }); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
return Json(new { error = ex.GetFullMessage(true) }); | |||
} | |||
} | |||
return Json(new { error = "Invalid Parameters" }); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult EditProfile(ProfileSettingsViewModel settings) | |||
{ | |||
if (ModelState.IsValid) | |||
{ | |||
try | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
User user = UserHelper.GetUser(db, User.Identity.Name); | |||
if (user != null) | |||
{ | |||
// Profile Info | |||
user.UserSettings.Website = settings.Website; | |||
user.UserSettings.Quote = settings.Quote; | |||
user.UserSettings.About = settings.About; | |||
UserHelper.EditAccount(db, Config, user); | |||
return Json(new { result = true }); | |||
} | |||
return Json(new { error = "User does not exist" }); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
return Json(new { error = ex.GetFullMessage(true) }); | |||
} | |||
} | |||
return Json(new { error = "Invalid Parameters" }); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult EditSecurity(SecuritySettingsViewModel settings) | |||
{ | |||
if (ModelState.IsValid) | |||
{ | |||
@@ -401,7 +630,6 @@ namespace Teknik.Areas.Users.Controllers | |||
if (user != null) | |||
{ | |||
bool changePass = false; | |||
string email = string.Format("{0}@{1}", User.Identity.Name, Config.EmailConfig.Domain); | |||
// Changing Password? | |||
if (!string.IsNullOrEmpty(settings.CurrentPassword) && (!string.IsNullOrEmpty(settings.NewPassword) || !string.IsNullOrEmpty(settings.NewPasswordConfirm))) | |||
{ | |||
@@ -488,18 +716,6 @@ namespace Teknik.Areas.Users.Controllers | |||
} | |||
user.SecuritySettings.TwoFactorKey = newKey; | |||
// Profile Info | |||
user.UserSettings.Website = settings.Website; | |||
user.UserSettings.Quote = settings.Quote; | |||
user.UserSettings.About = settings.About; | |||
// Blogs | |||
user.BlogSettings.Title = settings.BlogTitle; | |||
user.BlogSettings.Description = settings.BlogDesc; | |||
// Uploads | |||
user.UploadSettings.Encrypt = settings.Encrypt; | |||
UserHelper.EditAccount(db, Config, user, changePass, settings.NewPassword); | |||
// If they have a recovery email, let's send a verification | |||
@@ -528,6 +744,36 @@ namespace Teknik.Areas.Users.Controllers | |||
return Json(new { error = "Invalid Parameters" }); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult EditUpload(UploadSettingsViewModel settings) | |||
{ | |||
if (ModelState.IsValid) | |||
{ | |||
try | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
User user = UserHelper.GetUser(db, User.Identity.Name); | |||
if (user != null) | |||
{ | |||
// Profile Info | |||
user.UploadSettings.Encrypt = settings.Encrypt; | |||
UserHelper.EditAccount(db, Config, user); | |||
return Json(new { result = true }); | |||
} | |||
return Json(new { error = "User does not exist" }); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
return Json(new { error = ex.GetFullMessage(true) }); | |||
} | |||
} | |||
return Json(new { error = "Invalid Parameters" }); | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult Delete() | |||
@@ -913,7 +1159,7 @@ namespace Teknik.Areas.Users.Controllers | |||
model.Name = token.Name; | |||
model.LastDateUsed = token.LastDateUsed; | |||
return Json(new { result = new { token = newTokenStr, html = PartialView("~/Areas/User/Views/User/AuthToken.cshtml", model).RenderToString() } }); | |||
return Json(new { result = new { token = newTokenStr, html = PartialView("~/Areas/User/Views/User/Settings/AuthToken.cshtml", model).RenderToString() } }); | |||
} | |||
return Json(new { error = "Unable to generate Auth Token" }); | |||
} | |||
@@ -1022,5 +1268,31 @@ namespace Teknik.Areas.Users.Controllers | |||
return Json(new { error = ex.GetFullMessage(true) }); | |||
} | |||
} | |||
[HttpPost] | |||
[ValidateAntiForgeryToken] | |||
public ActionResult CreateInviteCodeLink(int inviteCodeId) | |||
{ | |||
try | |||
{ | |||
using (TeknikEntities db = new TeknikEntities()) | |||
{ | |||
InviteCode code = db.InviteCodes.Where(c => c.InviteCodeId == inviteCodeId).FirstOrDefault(); | |||
if (code != null) | |||
{ | |||
if (code.Owner.UserId == User.Info.UserId) | |||
{ | |||
return Json(new { result = Url.SubRouteUrl("user", "User.Register", new { inviteCode = code.Code })}); | |||
} | |||
return Json(new { error = "Invite Code not associated with this user"}); | |||
} | |||
return Json(new { error = "Invalid Invite Code" }); | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
return Json(new { error = ex.GetFullMessage(true) }); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.Attributes; | |||
namespace Teknik.Areas.Users.Models | |||
{ | |||
public class InviteCode | |||
{ | |||
public int InviteCodeId { get; set; } | |||
public bool Active { get; set; } | |||
[CaseSensitive] | |||
public string Code { get; set; } | |||
public virtual User Owner { get; set; } | |||
public virtual User ClaimedUser { get; set; } | |||
public InviteCode() | |||
{ | |||
Active = false; | |||
} | |||
} | |||
} |
@@ -24,6 +24,10 @@ namespace Teknik.Areas.Users.Models | |||
public DateTime LastSeen { get; set; } | |||
public virtual InviteCode ClaimedInviteCode { get; set; } | |||
public virtual ICollection<InviteCode> OwnedInviteCodes { get; set; } | |||
public AccountType AccountType { get; set; } | |||
public AccountStatus AccountStatus { get; set; } | |||
@@ -62,6 +66,8 @@ namespace Teknik.Areas.Users.Models | |||
Groups = new List<Group>(); | |||
TrustedDevices = new List<TrustedDevice>(); | |||
AuthTokens = new List<AuthToken>(); | |||
ClaimedInviteCode = null; | |||
OwnedInviteCodes = new List<InviteCode>(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,29 @@ | |||
$(document).ready(function () { | |||
$("#update_submit").click(function () { | |||
// Start Updating Animation | |||
$.blockUI({ message: '<div class="text-center"><h3>Updating...</h3></div>' }); | |||
blog_title = $("#update_blog_title").val(); | |||
blog_desc = $("#update_blog_description").val(); | |||
$.ajax({ | |||
type: "POST", | |||
url: editURL, | |||
data: AddAntiForgeryToken({ | |||
Title: blog_title, | |||
Description: blog_desc, | |||
}), | |||
success: function (html) { | |||
$.unblockUI(); | |||
if (html.result) { | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Settings Saved!</div>'); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
return false; | |||
}); | |||
}); |
@@ -0,0 +1,35 @@ | |||
$(document).ready(function () { | |||
$('[data-toggle="popover"]').popover(); | |||
$('[data-toggle="popover"]').on('shown.bs.popover', function () { | |||
var $this = $(this); | |||
setTimeout(function() { | |||
$this.popover('hide'); | |||
}, 3000); | |||
}); | |||
}); | |||
function copyCode(inviteCodeId, inviteCode) { | |||
copyTextToClipboard(inviteCode); | |||
$('#copyCode_' + inviteCodeId + '').popover('show'); | |||
} | |||
function createExternalLink(inviteCodeId) { | |||
$.ajax({ | |||
type: "POST", | |||
url: createExternalLinkURL, | |||
data: AddAntiForgeryToken({ inviteCodeId: inviteCodeId }), | |||
success: function (response) { | |||
if (response.result) { | |||
bootbox.dialog({ | |||
title: "Send this link to someone to claim this invite code.", | |||
message: '<input type="text" class="form-control" id="inviteCodeLink" onClick="this.select();" value="' + response.result + '">' | |||
}); | |||
} | |||
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>'); | |||
} | |||
} | |||
}); | |||
} |
@@ -0,0 +1,31 @@ | |||
$(document).ready(function () { | |||
$("#update_submit").click(function () { | |||
// Start Updating Animation | |||
$.blockUI({ message: '<div class="text-center"><h3>Updating...</h3></div>' }); | |||
website = $("#update_website").val(); | |||
quote = $("#update_quote").val(); | |||
about = $("#update_about").val(); | |||
$.ajax({ | |||
type: "POST", | |||
url: editURL, | |||
data: AddAntiForgeryToken({ | |||
Website: website, | |||
Quote: quote, | |||
About: about | |||
}), | |||
success: function (html) { | |||
$.unblockUI(); | |||
if (html.result) { | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Settings Saved!</div>'); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
return false; | |||
}); | |||
}); |
@@ -0,0 +1,49 @@ | |||
$(document).ready(function () { | |||
$("#reset_pass_send_submit").click(function () { | |||
var form = $('#reset_pass_send'); | |||
username = $("#reset_username").val(); | |||
$.ajax({ | |||
type: "POST", | |||
url: form.attr('action'), | |||
data: AddAntiForgeryToken({ | |||
username: username | |||
}), | |||
success: function (html) { | |||
if (html.result) { | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>The Password Reset Link has been sent to your recovery email.</div>'); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
return false; | |||
}); | |||
$("#setNewPass_submit").click(function () { | |||
var form = $('#setNewPass'); | |||
password = $("#setNewPass_Password").val(); | |||
confirmPassword = $("#setNewPass_ConfirmPassword").val(); | |||
$.ajax({ | |||
type: "POST", | |||
url: form.attr('action'), | |||
data: AddAntiForgeryToken({ | |||
Password: password, | |||
PasswordConfirm: confirmPassword | |||
}), | |||
success: function (html) { | |||
if (html.result) { | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Password has successfully been reset.</div>'); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
return false; | |||
}); | |||
}); |
@@ -1,5 +1,4 @@ | |||
๏ปฟ$(document).ready(function () { | |||
$("[name='update_upload_encrypt']").bootstrapSwitch(); | |||
$(document).ready(function () { | |||
$("[name='update_security_two_factor']").bootstrapSwitch(); | |||
$("[name='update_security_allow_trusted']").bootstrapSwitch(); | |||
@@ -10,18 +9,12 @@ | |||
data: AddAntiForgeryToken({}), | |||
success: function (html) { | |||
if (html.result) { | |||
window.location.reload(); | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-info alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Recovery Email Verification Sent.</div>'); | |||
} | |||
else { | |||
errorMsg = html; | |||
if (html.error) { | |||
errorMsg = html.error; | |||
if (html.error.message) { | |||
errorMsg = html.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -51,15 +44,8 @@ | |||
$("#authSetupStatus").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Success!</div>'); | |||
} | |||
else { | |||
errorMsg = html; | |||
if (html.error) { | |||
errorMsg = html.error; | |||
if (html.error.message) { | |||
errorMsg = html.error.message; | |||
} | |||
} | |||
$("#authSetupStatus").css('display', 'inline', 'important'); | |||
$("#authSetupStatus").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + errorMsg + '</div>'); | |||
$("#authSetupStatus").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -77,15 +63,8 @@ | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Successfully Cleared Trusted Devices</div>'); | |||
} | |||
else { | |||
errorMsg = html; | |||
if (html.error) { | |||
errorMsg = html.error; | |||
if (html.error.message) { | |||
errorMsg = html.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -119,15 +98,8 @@ | |||
}); | |||
} | |||
else { | |||
errorMsg = response; | |||
if (response.error) { | |||
errorMsg = response.error; | |||
if (response.error.message) { | |||
errorMsg = response.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#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>'); | |||
} | |||
} | |||
}); | |||
@@ -147,43 +119,8 @@ | |||
$('#authTokenList').html('<li class="list-group-item text-center" id="noAuthTokens">No Authentication Tokens</li>'); | |||
} | |||
else { | |||
errorMsg = response; | |||
if (response.error) { | |||
errorMsg = response.error; | |||
if (response.error.message) { | |||
errorMsg = response.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
}); | |||
$('#delete_account').click(function () { | |||
bootbox.confirm("Are you sure you want to delete your account?", function (result) { | |||
if (result) { | |||
$.ajax({ | |||
type: "POST", | |||
url: deleteUserURL, | |||
data: AddAntiForgeryToken({}), | |||
success: function (html) { | |||
if (html.result) { | |||
window.location.replace(homeUrl); | |||
} | |||
else { | |||
errorMsg = html; | |||
if (html.error) { | |||
errorMsg = html.error; | |||
if (html.error.message) { | |||
errorMsg = html.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#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>'); | |||
} | |||
} | |||
}); | |||
@@ -202,15 +139,9 @@ | |||
update_security_allow_trusted = $("#update_security_allow_trusted").is(":checked"); | |||
update_security_two_factor = $("#update_security_two_factor").is(":checked"); | |||
recovery = $("#update_recovery_email").val(); | |||
website = $("#update_website").val(); | |||
quote = $("#update_quote").val(); | |||
about = $("#update_about").val(); | |||
blog_title = $("#update_blog_title").val(); | |||
blog_desc = $("#update_blog_description").val(); | |||
upload_encrypt = $("#update_upload_encrypt").is(":checked"); | |||
$.ajax({ | |||
type: "POST", | |||
url: editUserURL, | |||
url: editURL, | |||
data: AddAntiForgeryToken({ | |||
CurrentPassword: current_password, | |||
NewPassword: password, | |||
@@ -218,13 +149,7 @@ | |||
PgpPublicKey: update_pgp_public_key, | |||
AllowTrustedDevices: update_security_allow_trusted, | |||
TwoFactorEnabled: update_security_two_factor, | |||
RecoveryEmail: recovery, | |||
Website: website, | |||
Quote: quote, | |||
About: about, | |||
BlogTitle: blog_title, | |||
BlogDesc: blog_desc, | |||
Encrypt: upload_encrypt | |||
RecoveryEmail: recovery | |||
}), | |||
success: function (html) { | |||
$.unblockUI(); | |||
@@ -238,15 +163,13 @@ | |||
} | |||
else | |||
{ | |||
window.location.reload(); | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Settings Saved!</div>'); | |||
} | |||
} | |||
else { | |||
var error = html; | |||
if (html.error) | |||
error = html.error; | |||
$("#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>' + error + '</div>'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -268,11 +191,8 @@ | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>The Password Reset Link has been sent to your recovery email.</div>'); | |||
} | |||
else { | |||
var error = html; | |||
if (html.error) | |||
error = html.error; | |||
$("#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>' + html.error + '</div>'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -296,11 +216,8 @@ | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Password has successfully been reset.</div>'); | |||
} | |||
else { | |||
var error = html; | |||
if (html.error) | |||
error = html.error; | |||
$("#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>' + html.error + '</div>'); | |||
$("#top_msg").html('<div class="alert alert-danger alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' + parseErrorMessage(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
@@ -320,15 +237,8 @@ function editAuthToken(authTokenId) { | |||
$('#authTokenName_' + authTokenId).html(response.result.name); | |||
} | |||
else { | |||
errorMsg = response; | |||
if (response.error) { | |||
errorMsg = response.error; | |||
if (response.error.message) { | |||
errorMsg = response.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#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>'); | |||
} | |||
} | |||
}); | |||
@@ -351,18 +261,11 @@ function deleteAuthToken(authTokenId) { | |||
} | |||
} | |||
else { | |||
errorMsg = response; | |||
if (response.error) { | |||
errorMsg = response.error; | |||
if (response.error.message) { | |||
errorMsg = response.error.message; | |||
} | |||
} | |||
$("#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>' + errorMsg + '</div>'); | |||
$("#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>'); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
$(document).ready(function () { | |||
$('#delete_account').click(function () { | |||
bootbox.confirm("Are you sure you want to delete your account?", function (result) { | |||
if (result) { | |||
$.ajax({ | |||
type: "POST", | |||
url: deleteUserURL, | |||
data: AddAntiForgeryToken({}), | |||
success: function (html) { | |||
if (html.result) { | |||
window.location.replace(homeUrl); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
}); | |||
}); |
@@ -0,0 +1,29 @@ | |||
$(document).ready(function () { | |||
$("[name='update_upload_encrypt']").bootstrapSwitch(); | |||
$("#update_submit").click(function () { | |||
// Start Updating Animation | |||
$.blockUI({ message: '<div class="text-center"><h3>Updating...</h3></div>' }); | |||
upload_encrypt = $("#update_upload_encrypt").is(":checked"); | |||
$.ajax({ | |||
type: "POST", | |||
url: editURL, | |||
data: AddAntiForgeryToken({ | |||
Encrypt: upload_encrypt | |||
}), | |||
success: function (html) { | |||
$.unblockUI(); | |||
if (html.result) { | |||
$("#top_msg").css('display', 'inline', 'important'); | |||
$("#top_msg").html('<div class="alert alert-success alert-dismissable"><button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>Settings Saved!</div>'); | |||
} | |||
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(html) + '</div>'); | |||
} | |||
} | |||
}); | |||
return false; | |||
}); | |||
}); |
@@ -1,4 +1,4 @@ | |||
๏ปฟusing System.Collections.Generic; | |||
using System.Collections.Generic; | |||
using System.Web.Mvc; | |||
using System.Web.Optimization; | |||
using Teknik.Configuration; | |||
@@ -59,6 +59,46 @@ namespace Teknik.Areas.Users | |||
new { controller = "User", action = "Settings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.SecuritySettings", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
new List<string>() { config.Host }, // domains | |||
"Settings/Security", // URL with parameters | |||
new { controller = "User", action = "SecuritySettings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.ProfileSettings", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
new List<string>() { config.Host }, // domains | |||
"Settings/Profile", // URL with parameters | |||
new { controller = "User", action = "ProfileSettings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.InviteSettings", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
new List<string>() { config.Host }, // domains | |||
"Settings/Invites", // URL with parameters | |||
new { controller = "User", action = "InviteSettings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.BlogSettings", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
new List<string>() { config.Host }, // domains | |||
"Settings/Blog", // URL with parameters | |||
new { controller = "User", action = "BlogSettings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.UploadSettings", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
new List<string>() { config.Host }, // domains | |||
"Settings/Uploads", // URL with parameters | |||
new { controller = "User", action = "UploadSettings" }, // Parameter defaults | |||
new[] { typeof(Controllers.UserController).Namespace } | |||
); | |||
context.MapSubdomainRoute( | |||
"User.ResetPassword", // Route name | |||
new List<string>() { "user" }, // Subdomains | |||
@@ -123,11 +163,37 @@ namespace Teknik.Areas.Users | |||
"~/Scripts/bootstrap-switch.js", | |||
"~/Areas/User/Scripts/User.js")); | |||
// Register Script Bundle | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/reset", config.CdnHost).Include( | |||
"~/Areas/User/Scripts/ResetPass.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings", config.CdnHost).Include( | |||
"~/Scripts/bootbox/bootbox.min.js", | |||
"~/Areas/User/Scripts/Settings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings/blog", config.CdnHost).Include( | |||
"~/Scripts/jquery.blockUI.js", | |||
"~/Areas/User/Scripts/BlogSettings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings/invite", config.CdnHost).Include( | |||
"~/Areas/User/Scripts/InviteSettings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings/profile", config.CdnHost).Include( | |||
"~/Scripts/jquery.blockUI.js", | |||
"~/Areas/User/Scripts/ProfileSettings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings/security", config.CdnHost).Include( | |||
"~/Scripts/jquery.blockUI.js", | |||
"~/Scripts/bootstrap-switch.js", | |||
"~/Areas/User/Scripts/SecuritySettings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/user/settings/upload", config.CdnHost).Include( | |||
"~/Scripts/jquery.blockUI.js", | |||
"~/Scripts/bootstrap-switch.js", | |||
"~/Areas/User/Scripts/UploadSettings.js")); | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/checkAuthCode", config.CdnHost).Include( | |||
"~/Areas/User/Scripts/CheckAuthCode.js")); | |||
// Register Script Bundle | |||
BundleTable.Bundles.Add(new CdnScriptBundle("~/bundles/profile", config.CdnHost).Include( | |||
"~/Scripts/bootbox/bootbox.min.js", | |||
"~/Areas/User/Scripts/Profile.js")); | |||
@@ -135,6 +201,12 @@ namespace Teknik.Areas.Users | |||
// Register Style Bundles | |||
BundleTable.Bundles.Add(new CdnStyleBundle("~/Content/user", config.CdnHost).Include( | |||
"~/Content/bootstrap-switch/bootstrap3/bootstrap-switch.css")); | |||
BundleTable.Bundles.Add(new CdnStyleBundle("~/Content/user/settings/security", config.CdnHost).Include( | |||
"~/Content/bootstrap-switch/bootstrap3/bootstrap-switch.css")); | |||
BundleTable.Bundles.Add(new CdnStyleBundle("~/Content/user/settings/upload", config.CdnHost).Include( | |||
"~/Content/bootstrap-switch/bootstrap3/bootstrap-switch.css")); | |||
} | |||
} | |||
} | |||
} |
@@ -186,6 +186,11 @@ namespace Teknik.Areas.Users.Utility | |||
} | |||
} | |||
public static void EditAccount(TeknikEntities db, Config config, User user) | |||
{ | |||
EditAccount(db, config, user, false, string.Empty); | |||
} | |||
public static void EditAccount(TeknikEntities db, Config config, User user, bool changePass, string password) | |||
{ | |||
try | |||
@@ -656,6 +661,34 @@ namespace Teknik.Areas.Users.Utility | |||
db.SaveChanges(); | |||
} | |||
// Delete Owned Invite Codes | |||
if (user.OwnedInviteCodes != null) | |||
{ | |||
foreach (InviteCode code in user.OwnedInviteCodes) | |||
{ | |||
db.InviteCodes.Remove(code); | |||
} | |||
db.SaveChanges(); | |||
} | |||
// Delete Claimed Invite Code | |||
if (user.ClaimedInviteCode != null) | |||
{ | |||
db.InviteCodes.Remove(user.ClaimedInviteCode); | |||
db.SaveChanges(); | |||
} | |||
// Delete Auth Tokens | |||
List<AuthToken> authTokens = db.AuthTokens.Where(t => t.User.UserId == user.UserId).ToList(); | |||
if (authTokens != null) | |||
{ | |||
foreach (AuthToken authToken in authTokens) | |||
{ | |||
db.AuthTokens.Remove(authToken); | |||
} | |||
db.SaveChanges(); | |||
} | |||
// Delete User | |||
db.Users.Remove(user); | |||
db.SaveChanges(); |
@@ -0,0 +1,22 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class BlogSettingsViewModel : SettingsViewModel | |||
{ | |||
public string Title { get; set; } | |||
public string Description { get; set; } | |||
public BlogSettingsViewModel() | |||
{ | |||
Title = string.Empty; | |||
Description = string.Empty; | |||
} | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class InviteCodeViewModel : ViewModelBase | |||
{ | |||
public int InviteCodeId { get; set; } | |||
public bool Active { get; set; } | |||
public string Code { get; set; } | |||
public virtual Models.User Owner { get; set; } | |||
public virtual Models.User ClaimedUser { get; set; } | |||
} | |||
} |
@@ -0,0 +1,21 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class InviteSettingsViewModel : SettingsViewModel | |||
{ | |||
public List<InviteCodeViewModel> AvailableCodes { get; set; } | |||
public List<InviteCodeViewModel> ClaimedCodes { get; set; } | |||
public InviteSettingsViewModel() | |||
{ | |||
AvailableCodes = new List<InviteCodeViewModel>(); | |||
ClaimedCodes = new List<InviteCodeViewModel>(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using System.Web.Mvc; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class ProfileSettingsViewModel : SettingsViewModel | |||
{ | |||
[AllowHtml] | |||
public string About { get; set; } | |||
public string Website { get; set; } | |||
public string Quote { get; set; } | |||
public ProfileSettingsViewModel() | |||
{ | |||
About = string.Empty; | |||
Website = string.Empty; | |||
Quote = string.Empty; | |||
} | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
๏ปฟusing System; | |||
using System; | |||
using System.ComponentModel.DataAnnotations; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.Utilities; | |||
@@ -24,6 +24,9 @@ namespace Teknik.Areas.Users.ViewModels | |||
[DataType(DataType.Password)] | |||
public string ConfirmPassword { get; set; } | |||
[Display(Name = "InviteCode")] | |||
public string InviteCode { get; set; } | |||
[Display(Name = "Recovery Email")] | |||
[DataType(DataType.EmailAddress)] | |||
public string RecoveryEmail { get; set; } | |||
@@ -34,4 +37,4 @@ namespace Teknik.Areas.Users.ViewModels | |||
public string ReturnUrl { get; set; } | |||
} | |||
} | |||
} |
@@ -0,0 +1,50 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using System.Web.Mvc; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class SecuritySettingsViewModel : SettingsViewModel | |||
{ | |||
[AllowHtml] | |||
public string CurrentPassword { get; set; } | |||
[AllowHtml] | |||
public string NewPassword { get; set; } | |||
[AllowHtml] | |||
public string NewPasswordConfirm { get; set; } | |||
public string PgpPublicKey { get; set; } | |||
public string RecoveryEmail { get; set; } | |||
public bool RecoveryVerified { get; set; } | |||
public bool AllowTrustedDevices { get; set; } | |||
public bool TwoFactorEnabled { get; set; } | |||
public string TwoFactorKey { get; set; } | |||
public int TrustedDeviceCount { get; set; } | |||
public List<AuthTokenViewModel> AuthTokens { get; set; } | |||
public SecuritySettingsViewModel() | |||
{ | |||
TrustedDeviceCount = 0; | |||
AuthTokens = new List<AuthTokenViewModel>(); | |||
RecoveryEmail = string.Empty; | |||
RecoveryVerified = false; | |||
AllowTrustedDevices = false; | |||
TwoFactorEnabled = false; | |||
TwoFactorKey = string.Empty; | |||
PgpPublicKey = string.Empty; | |||
} | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
๏ปฟusing System; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
@@ -13,16 +13,6 @@ namespace Teknik.Areas.Users.ViewModels | |||
public string Username { get; set; } | |||
public int TrustedDeviceCount { get; set; } | |||
public List<AuthTokenViewModel> AuthTokens { get; set; } | |||
public UserSettings UserSettings { get; set; } | |||
public SecuritySettings SecuritySettings { get; set; } | |||
public BlogSettings BlogSettings { get; set; } | |||
public UploadSettings UploadSettings { get; set; } | |||
public string Page { get; set; } | |||
} | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Web; | |||
using Teknik.Areas.Users.Models; | |||
using Teknik.ViewModels; | |||
namespace Teknik.Areas.Users.ViewModels | |||
{ | |||
public class UploadSettingsViewModel : SettingsViewModel | |||
{ | |||
public bool Encrypt { get; set; } | |||
public UploadSettingsViewModel() | |||
{ | |||
Encrypt = false; | |||
} | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
๏ปฟ@model Teknik.Areas.Users.ViewModels.RegisterViewModel | |||
@model Teknik.Areas.Users.ViewModels.RegisterViewModel | |||
@using Teknik.Utilities | |||
@@ -17,19 +17,30 @@ | |||
<form id="registrationForm" action="@Url.SubRouteUrl("user", "User.Register")" method="post" accept-charset="UTF-8"> | |||
<input name="Register.ReturnUrl" id="registerReturnUrl" type="hidden" value="@Model.ReturnUrl" /> | |||
<div class="form-group"> | |||
<input type="text" class="form-control" id="registerUsername" value="" placeholder="Username" name="Register.Username" data-val-required="The Username field is required." data-val="true"/> | |||
<label for="registerUsername">Username</label> | |||
<input type="text" class="form-control" id="registerUsername" value="" placeholder="Bob" name="Register.Username" data-val-required="The Username field is required." data-val="true"/> | |||
</div> | |||
<div class="form-group"> | |||
<input type="password" class="form-control" id="registerPassword" value="" placeholder="Password" name="Register.Password" data-val-required="The Password field is required." data-val="true"/> | |||
<label for="registerPassword">Password</label> | |||
<input type="password" class="form-control" id="registerPassword" value="" placeholder="********" name="Register.Password" data-val-required="The Password field is required." data-val="true"/> | |||
</div> | |||
<div class="form-group"> | |||
<input type="password" class="form-control" id="registerConfirmPassword" value="" placeholder="Confirm Password" name="Register.ConfirmPassword" data-val-required="The Confirm Password field is required." data-val="true" /> | |||
<label for="registerConfirmPassword">Confirm Password</label> | |||
<input type="password" class="form-control" id="registerConfirmPassword" value="" placeholder="********" name="Register.ConfirmPassword" data-val-required="The Confirm Password field is required." data-val="true"/> | |||
</div> | |||
<div class="form-group"> | |||
<input type="text" class="form-control" id="registerRecoveryEmail" value="" placeholder="Recovery Email (Optional)" name="Register.RecoveryEmail" /> | |||
<label for="registerInviteCode">Invite Code@(Model.Config.UserConfig.InviteCodeRequired ? string.Empty : " (Optional)")</label> | |||
<input type="text" class="form-control" id="registerInviteCode" value="@Model.InviteCode" placeholder="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" name="Register.InviteCode"/> | |||
</div> | |||
<div class="form-group"> | |||
<textarea class="form-control" id="registerPublicKey" name="Register.PublicKey" placeholder="PGP Public Key (Optional)" title="enter your pgp public key" rows="5"></textarea> | |||
<label for="registerRecoveryEmail">Recovery Email (Optional)</label> | |||
<input type="text" class="form-control" id="registerRecoveryEmail" value="" placeholder="user@example.com" name="Register.RecoveryEmail"/> | |||
</div> | |||
<div class="form-group"> | |||
<label for="registerPublicKey">PGP Public Key (Optional)</label> | |||
<textarea class="form-control" id="registerPublicKey" name="Register.PublicKey" placeholder="-----BEGIN PGP PUBLIC KEY BLOCK----- | |||
... | |||
-----END PGP PUBLIC KEY BLOCK-----" title="enter your pgp public key" rows="5"></textarea> | |||
</div> | |||
<p class="text-center"> | |||
<small> | |||
@@ -48,4 +59,4 @@ | |||
else | |||
{ | |||
<h3>Registration has been disabled</h3> | |||
} | |||
} |
@@ -1,8 +1,8 @@ | |||
๏ปฟ@model Teknik.Areas.Users.ViewModels.ResetPasswordViewModel | |||
@model Teknik.Areas.Users.ViewModels.ResetPasswordViewModel | |||
@using Teknik.Utilities | |||
@Scripts.Render("~/bundles/user") | |||
@Scripts.Render("~/bundles/user/reset") | |||
<div class="container"> | |||
<div class="row"> | |||
@@ -31,4 +31,4 @@ | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> |
@@ -1,8 +1,8 @@ | |||
๏ปฟ@model Teknik.Areas.Users.ViewModels.ResetPasswordVerificationViewModel | |||
@model Teknik.Areas.Users.ViewModels.ResetPasswordVerificationViewModel | |||
@using Teknik.Utilities | |||
@Scripts.Render("~/bundles/user") | |||
@Scripts.Render("~/bundles/user/reset") | |||
<div class="container"> | |||
<div class="row"> |
@@ -1,255 +0,0 @@ | |||
๏ปฟ@model Teknik.Areas.Users.ViewModels.SettingsViewModel | |||
@using Teknik.Utilities | |||
@using Teknik.Areas.Users.ViewModels | |||
<script> | |||
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")'; | |||
var editUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Edit" })'; | |||
var deleteUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Delete" })'; | |||
var resendVerifyURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ResendVerifyRecoveryEmail"})'; | |||
var confirmAuthSetupURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "VerifyAuthenticatorCode" })'; | |||
var clearTrustedDevicesURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ClearTrustedDevices" })'; | |||
var generateTokenURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateToken" })'; | |||
var revokeAllTokensURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "RevokeAllTokens" })'; | |||
var editTokenNameURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditTokenName" })'; | |||
var deleteTokenURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "DeleteToken" })'; | |||
</script> | |||
@Styles.Render("~/Content/user") | |||
@Scripts.Render("~/bundles/user") | |||
<div class="container"> | |||
@if (!Model.Error) | |||
{ | |||
<div class="modal fade" id="authenticatorSetup" tabindex="-1" role="dialog" aria-labelledby="authenticatorSetupLabel" aria-hidden="true"> | |||
<div class="modal-dialog"> | |||
<div class="modal-content"> | |||
<div class="modal-header"> | |||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button> | |||
<h4 class="modal-title" id="authSetupTitleLabel">Set Up a Third Party App to Generate Codes</h4> | |||
</div> | |||
<div class="modal-body"> | |||
<div class="row"> | |||
<div class="col-sm-12 text-center"> | |||
<div id="authSetupStatus"></div> | |||
</div> | |||
</div> | |||
<form class="form" action="##" method="post" id="confirmAuthSetup"> | |||
<p>To get a third party app working, either scan the QR code below or type the secret key into the app.</p> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">QR Code:</p> | |||
</div> | |||
<div class="col-sm-8"> | |||
<img id="authQRCode" src="@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = Model.SecuritySettings.TwoFactorKey })" width="200" height="200" alt="qr code" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">Secret Key:</p> | |||
</div> | |||
<div class="col-sm-8"> | |||
<span class="text-success" id="authSetupSecretKey">@Model.SecuritySettings.TwoFactorKey</span> | |||
</div> | |||
</div> | |||
<hr /> | |||
<p>To confirm the third party app is set up correctly, enter the security code that appears on your phone.</p> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">Security Code:</p> | |||
</div> | |||
<div class="col-sm-6"> | |||
<input class="form-control" id="auth_setup_code" name="auth_setup_code" title="Authenticator Security Code" type="text" /> | |||
</div> | |||
</div> | |||
<hr /> | |||
<div class="form-group text-right"> | |||
<button class="btn btn-primary" id="auth_setup_verify" type="button" name="auth_setup_verify">Verify</button> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-12"> | |||
<form class="form" action="##" method="post" id="updateForm"> | |||
<input name="update_userid" id="update_userid" type="hidden" value="@Model.UserID" /> | |||
<!-- Tab Navigation --> | |||
<ul class="nav nav-tabs" id="settingTabs"> | |||
<li class="active"><a href="#profile" data-toggle="tab"> Profile </a></li> | |||
<li><a href="#security" data-toggle="tab"> Security </a></li> | |||
<li><a href="#blog" data-toggle="tab"> Blog </a></li> | |||
<li><a href="#uploads" data-toggle="tab"> Uploads </a></li> | |||
</ul> | |||
<div class="tab-content"> | |||
<!-- Profile Settings --> | |||
<div class="tab-pane active" id="profile"> | |||
<div class="row"> | |||
<div class="form-group col-sm-4"> | |||
<label for="update_website"><h4>Website</h4></label> | |||
<input class="form-control" id="update_website" name="update_website" placeholder="http://www.noneofyourbusiness.com/" title="enter your website" type="text" value="@Model.UserSettings.Website" /> | |||
</div> | |||
<div class="form-group col-sm-8"> | |||
<label for="update_quote"><h4>Quote</h4></label> | |||
<input class="form-control" id="update_quote" name="update_quote" placeholder="I have a dream!" title="enter a memorable quote" type="text" value="@Model.UserSettings.Quote" maxlength="140" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_about"><h4>About Yourself</h4></label> | |||
<textarea class="form-control" name="update_about" id="update_about" placeholder="I'm awesome" title="enter any information you want to share with the world." data-provide="markdown" rows="10">@Model.UserSettings.About</textarea> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- Security Settings --> | |||
<div class="tab-pane" id="security"> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password_current"><h4>Current Password</h4></label> | |||
<input class="form-control" name="update_password_current" id="update_password_current" placeholder="current password" title="enter your current password." type="password" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password"><h4>New Password</h4></label> | |||
<input class="form-control" name="update_password" id="update_password" placeholder="new password" title="enter your password." type="password" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password_confirm"><h4>Verify New Password</h4></label> | |||
<input class="form-control" name="update_password_confirm" id="update_password_confirm" placeholder="new password confirmed" title="enter your password again." type="password" /> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="col-sm-8"> | |||
<label for="update_pgp_public_key"><h4>Public Key</h4></label> | |||
<textarea class="form-control" id="update_pgp_public_key" name="update_pgp_public_key" placeholder="Public Key Here" title="enter your pgp public key" rows="15">@Model.SecuritySettings.PGPSignature</textarea> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-4 text-left"> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_recovery_email"><h4>Recovery Email</h4></label> | |||
<input class="form-control" name="update_recovery_email" id="update_recovery_email" placeholder="user@example.com" title="enter a recovery email." type="text" value="@Model.SecuritySettings.RecoveryEmail" /> | |||
@if (!string.IsNullOrEmpty(Model.SecuritySettings.RecoveryEmail)) | |||
{ | |||
<p class="form-control-static"> | |||
@if (Model.SecuritySettings.RecoveryVerified) | |||
{ | |||
<span class="text-success"><i class="fa fa-check"></i> Verified</span> | |||
} | |||
else | |||
{ | |||
<span class="text-danger"><i class="fa fa-ban"></i> Unverified</span> <small><a href="#" class="text-primary" id="ResendVerification"><i class="fa fa-repeat"></i> Resend</a></small> | |||
} | |||
</p> | |||
} | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12 text-left"> | |||
<label for="update_security_two_factor"><h4>Enable Two Factor Authentication</h4></label> | |||
<div class="checkbox"> | |||
<label> | |||
<input id="update_security_two_factor" name="update_security_two_factor" title="whether two factor authentication should occur for this account" type="checkbox" value="true" @(Model.SecuritySettings.TwoFactorEnabled ? "checked" : string.Empty) /> | |||
</label> | |||
</div> | |||
<p class="form-control-static @(Model.SecuritySettings.TwoFactorEnabled ? string.Empty : "hide")" id="setupAuthenticatorLink"> | |||
<small><a href="#" class="text-primary" id="SetupAuthenticator" data-toggle="modal" data-target="#authenticatorSetup"><i class="fa fa-lock"></i> Set Up Authenticator</a></small> | |||
</p> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12 text-left"> | |||
<label for="update_security_allow_trusted"><h4>Allow Trusted Devices</h4></label> | |||
<div class="checkbox"> | |||
<label> | |||
<input id="update_security_allow_trusted" name="update_security_allow_trusted" title="whether a device could be cached to bypass two factor authentication" type="checkbox" value="true" @(Model.SecuritySettings.AllowTrustedDevices ? "checked" : string.Empty) /> | |||
</label> | |||
</div> | |||
<p class="form-control-static @(Model.SecuritySettings.AllowTrustedDevices ? string.Empty : "hide")" id="ClearDevicesLink"> | |||
<small><a href="#" class="text-primary" id="ClearDevices">Clear Trusted Devices (@Model.TrustedDeviceCount)</a></small> | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="col-sm-8"> | |||
<br /> | |||
<label for="authTokens"><h4>Authentication Tokens</h4></label><span class="pull-right"><button type="button" class="btn btn-default" id="generate_token">Generate Token</button> <button type="button" class="btn btn-danger" id="revoke_all_tokens">Revoke All</button></span> | |||
<div id="authTokens" style="overflow-y: auto; max-height: 400px;"> | |||
<ul class="list-group" id="authTokenList"> | |||
@if (Model.AuthTokens.Any()) | |||
{ | |||
foreach (AuthTokenViewModel token in Model.AuthTokens) | |||
{ | |||
@Html.Partial("AuthToken", token) | |||
} | |||
} | |||
else | |||
{ | |||
<li class="list-group-item text-center" id="noAuthTokens">No Authentication Tokens</li> | |||
} | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- Blog Settings --> | |||
<div class="tab-pane" id="blog"> | |||
<div class="row"> | |||
<div class="form-group col-sm-6"> | |||
<label for="update_blog_title"><h4>Title</h4></label> | |||
<input class="form-control" id="update_blog_title" name="update_blog_title" placeholder="click bait" title="enter your blog's title" type="text" value="@Model.BlogSettings.Title" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label for="update_blog_description"><h4>Description</h4></label> | |||
<input class="form-control" id="update_blog_description" name="update_blog_description" placeholder="This blog is not worth reading." title="enter your blog's description" type="text" value="@Model.BlogSettings.Description" /> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- Upload Settings --> | |||
<div class="tab-pane" id="uploads"> | |||
<div class="row"> | |||
<div class="col-sm-6"> | |||
<div class="checkbox"> | |||
<label> | |||
<label for="update_upload_encrypt"><h4>Encrypt in Browser</h4></label> | |||
<input id="update_upload_encrypt" name="update_upload_encrypt" title="whether the file should be encrypted in the browser before upload" type="checkbox" value="true" @(Model.UploadSettings.Encrypt ? "checked" : string.Empty) /> | |||
</label> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<!-- Save Settings --> | |||
<div class="row"> | |||
<div class="form-group col-sm-10"> | |||
<br /> | |||
<button class="btn btn-lg btn-success" id="update_submit" type="submit"><i class="glyphicon glyphicon-ok-sign"></i> Save</button> | |||
<button class="btn btn-lg" type="reset"><i class="glyphicon glyphicon-repeat"></i> Reset</button> | |||
</div> | |||
<div class="form-group col-sm-2"> | |||
<br /> | |||
<button type="button" class="btn btn-danger" id="delete_account">Delete Account</button> | |||
</div> | |||
</div> | |||
</form> | |||
</div><!--/col-9--> | |||
</div><!--/row--> | |||
} | |||
else | |||
{ | |||
<div class="row"> | |||
<div class="col-sm-12 text-center"> | |||
<h2>Sorry, but I couldn't find that user.</h2> | |||
</div> | |||
</div> | |||
} | |||
</div> |
@@ -0,0 +1,36 @@ | |||
@model Teknik.Areas.Users.ViewModels.BlogSettingsViewModel | |||
@using Teknik.Utilities | |||
@using Teknik.Areas.Users.ViewModels | |||
@{ | |||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml"; | |||
} | |||
<script> | |||
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditBlog" })'; | |||
</script> | |||
@Styles.Render("~/Content/user/settings/blog") | |||
@Scripts.Render("~/bundles/user/settings/blog") | |||
<form class="form" action="##" method="post" id="updateForm"> | |||
<div class="row"> | |||
<div class="form-group col-sm-6"> | |||
<label for="update_blog_title"><h4>Title</h4></label> | |||
<input class="form-control" id="update_blog_title" name="update_blog_title" placeholder="click bait" title="enter your blog's title" type="text" value="@Model.Title" /> | |||
</div> | |||
<div class="form-group col-sm-6"> | |||
<label for="update_blog_description"><h4>Description</h4></label> | |||
<input class="form-control" id="update_blog_description" name="update_blog_description" placeholder="This blog is not worth reading." title="enter your blog's description" type="text" value="@Model.Description" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-10"> | |||
<br /> | |||
<button class="btn btn-lg btn-success" id="update_submit" type="submit"><i class="glyphicon glyphicon-ok-sign"></i> Save</button> | |||
<button class="btn btn-lg" type="reset"><i class="glyphicon glyphicon-repeat"></i> Reset</button> | |||
</div> | |||
</div> | |||
</form> |
@@ -0,0 +1,21 @@ | |||
@using Teknik.Utilities | |||
@model Teknik.Areas.Users.ViewModels.InviteCodeViewModel | |||
@{ | |||
bool codeClaimed = Model.ClaimedUser != null; | |||
} | |||
<li class="list-group-item @(Model.Active ? string.Empty : ".disabled")" id="inviteCode_@Model.InviteCodeId"> | |||
@if (!codeClaimed) | |||
{ | |||
<div class="btn-group btn-group-sm pull-right" role="group" aria-label="..."> | |||
<button type="button" class="btn btn-default" id="copyCode_@Model.InviteCodeId" onclick="copyCode(@(Model.InviteCodeId), '@(Model.Code)');" data-toggle="popover" data-trigger="manual" data-placement="top" data-content="Copied to Clipboard" data-container="body"><i class="fa fa-clipboard"></i></button> | |||
<button type="button" class="btn btn-default" onclick="createExternalLink(@Model.InviteCodeId);"><i class="fa fa-external-link"></i></button> | |||
</div> | |||
} | |||
<h4 class="list-group-item-heading" id="inviteCode_Code_@Model.InviteCodeId">@Model.Code</h4> | |||
@if (codeClaimed) | |||
{ | |||
<p class="list-group-item-text">Claimed by <a href="@Url.SubRouteUrl("user", "User.ViewProfile", new {username = Model.ClaimedUser.Username})">@Model.ClaimedUser.Username</a></p> | |||
} | |||
</li> |
@@ -0,0 +1,59 @@ | |||
@model Teknik.Areas.Users.ViewModels.InviteSettingsViewModel | |||
@using Teknik.Utilities | |||
@using Teknik.Areas.Users.ViewModels | |||
@{ | |||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml"; | |||
} | |||
@Styles.Render("~/Content/user/settings/invite") | |||
@Scripts.Render("~/bundles/user/settings/invite") | |||
<script> | |||
var createExternalLinkURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "CreateInviteCodeLink" })'; | |||
</script> | |||
<div class="row"> | |||
<div class="col-sm-10 col-sm-offset-1"> | |||
<br /> | |||
<label for="availableCodes"><h4>Available Invite Codes</h4></label> | |||
<div id="availableCodes" style="overflow-y: auto; max-height: 400px;"> | |||
<ul class="list-group" id="availableCodeList"> | |||
@if (Model.AvailableCodes.Any()) | |||
{ | |||
foreach (InviteCodeViewModel code in Model.AvailableCodes) | |||
{ | |||
@Html.Partial("Settings/InviteCode", code) | |||
} | |||
} | |||
else | |||
{ | |||
<li class="list-group-item text-center" id="noAvailableCodes">No Invite Codes Available</li> | |||
} | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-10 col-sm-offset-1"> | |||
<br /> | |||
<label for="claimedCodes"><h4>Claimed Invite Codes</h4></label> | |||
<div id="claimedCodes" style="overflow-y: auto; max-height: 400px;"> | |||
<ul class="list-group" id="claimedCodeList"> | |||
@if (Model.ClaimedCodes.Any()) | |||
{ | |||
foreach (InviteCodeViewModel code in Model.ClaimedCodes) | |||
{ | |||
@Html.Partial("Settings/InviteCode", code) | |||
} | |||
} | |||
else | |||
{ | |||
<li class="list-group-item text-center" id="noClaimedCodes">No Invite Codes have been Claimed</li> | |||
} | |||
</ul> | |||
</div> | |||
</div> | |||
</div> |
@@ -0,0 +1,41 @@ | |||
@model Teknik.Areas.Users.ViewModels.ProfileSettingsViewModel | |||
@using Teknik.Utilities | |||
@using Teknik.Areas.Users.ViewModels | |||
@{ | |||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml"; | |||
} | |||
<script> | |||
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditProfile" })'; | |||
</script> | |||
@Styles.Render("~/Content/user/settings/profile") | |||
@Scripts.Render("~/bundles/user/settings/profile") | |||
<form class="form" action="##" method="post" id="updateForm"> | |||
<div class="row"> | |||
<div class="form-group col-sm-4"> | |||
<label for="update_website"><h4>Website</h4></label> | |||
<input class="form-control" id="update_website" name="update_website" placeholder="http://www.noneofyourbusiness.com/" title="enter your website" type="text" value="@Model.Website" /> | |||
</div> | |||
<div class="form-group col-sm-8"> | |||
<label for="update_quote"><h4>Quote</h4></label> | |||
<input class="form-control" id="update_quote" name="update_quote" placeholder="I have a dream!" title="enter a memorable quote" type="text" value="@Model.Quote" maxlength="140" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_about"><h4>About Yourself</h4></label> | |||
<textarea class="form-control" name="update_about" id="update_about" placeholder="I'm awesome" title="enter any information you want to share with the world." data-provide="markdown" rows="10">@Model.About</textarea> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-10"> | |||
<br /> | |||
<button class="btn btn-lg btn-success" id="update_submit" type="submit"><i class="glyphicon glyphicon-ok-sign"></i> Save</button> | |||
<button class="btn btn-lg" type="reset"><i class="glyphicon glyphicon-repeat"></i> Reset</button> | |||
</div> | |||
</div> | |||
</form> |
@@ -0,0 +1,178 @@ | |||
@model Teknik.Areas.Users.ViewModels.SecuritySettingsViewModel | |||
@using Teknik.Utilities | |||
@using Teknik.Areas.Users.ViewModels | |||
@{ | |||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml"; | |||
} | |||
<script> | |||
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")'; | |||
var editURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditSecurity" })'; | |||
var resendVerifyURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ResendVerifyRecoveryEmail"})'; | |||
var confirmAuthSetupURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "VerifyAuthenticatorCode" })'; | |||
var clearTrustedDevicesURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "ClearTrustedDevices" })'; | |||
var generateTokenURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateToken" })'; | |||
var revokeAllTokensURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "RevokeAllTokens" })'; | |||
var editTokenNameURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "EditTokenName" })'; | |||
var deleteTokenURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "DeleteToken" })'; | |||
</script> | |||
@Styles.Render("~/Content/user/settings/security") | |||
@Scripts.Render("~/bundles/user/settings/security") | |||
<div class="modal fade" id="authenticatorSetup" tabindex="-1" role="dialog" aria-labelledby="authenticatorSetupLabel" aria-hidden="true"> | |||
<div class="modal-dialog"> | |||
<div class="modal-content"> | |||
<div class="modal-header"> | |||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span></button> | |||
<h4 class="modal-title" id="authSetupTitleLabel">Set Up a Third Party App to Generate Codes</h4> | |||
</div> | |||
<div class="modal-body"> | |||
<div class="row"> | |||
<div class="col-sm-12 text-center"> | |||
<div id="authSetupStatus"></div> | |||
</div> | |||
</div> | |||
<form class="form" action="##" method="post" id="confirmAuthSetup"> | |||
<p>To get a third party app working, either scan the QR code below or type the secret key into the app.</p> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">QR Code:</p> | |||
</div> | |||
<div class="col-sm-8"> | |||
<img id="authQRCode" src="@Url.SubRouteUrl("user", "User.Action", new { action = "GenerateAuthQrCode", key = Model.TwoFactorKey })" width="200" height="200" alt="qr code" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">Secret Key:</p> | |||
</div> | |||
<div class="col-sm-8"> | |||
<span class="text-success" id="authSetupSecretKey">@Model.TwoFactorKey</span> | |||
</div> | |||
</div> | |||
<hr /> | |||
<p>To confirm the third party app is set up correctly, enter the security code that appears on your phone.</p> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<p class="text-muted">Security Code:</p> | |||
</div> | |||
<div class="col-sm-6"> | |||
<input class="form-control" id="auth_setup_code" name="auth_setup_code" title="Authenticator Security Code" type="text" /> | |||
</div> | |||
</div> | |||
<hr /> | |||
<div class="form-group text-right"> | |||
<button class="btn btn-primary" id="auth_setup_verify" type="button" name="auth_setup_verify">Verify</button> | |||
</div> | |||
</form> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<form class="form" action="##" method="post" id="updateForm"> | |||
<div class="row"> | |||
<div class="col-sm-4"> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password_current"><h4>Current Password</h4></label> | |||
<input class="form-control" name="update_password_current" id="update_password_current" placeholder="current password" title="enter your current password." type="password" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password"><h4>New Password</h4></label> | |||
<input class="form-control" name="update_password" id="update_password" placeholder="new password" title="enter your password." type="password" /> | |||
</div> | |||
</div> | |||
<div class="row"> | |||
<div class="form-group col-sm-12"> | |||
<label for="update_password_confirm"><h4>Verify New Password</h4></label> | |||
<input class="form-control" name="update_password_confirm" id="update_password_confirm" placeholder="new password confirmed" title="enter your password again." type="password" /> | |||
</div> | |||
</div> | |||