mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
- Implemented invite codes to use for registration.
- Reorganized settings pages into individual pages.
This commit is contained in:
parent
61e0204361
commit
a7c314d728
@ -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;
|
||||
|
||||
SettingsViewModel model = new SettingsViewModel();
|
||||
ViewBag.Title = "User Does Not Exist - " + Config.Title;
|
||||
ViewBag.Description = "The User does not exist";
|
||||
return Redirect(Url.SubRouteUrl("user", "User.SecuritySettings"));
|
||||
}
|
||||
|
||||
[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 = "Settings - " + Config.Title;
|
||||
ViewBag.Description = "Your " + Config.Title + " Settings";
|
||||
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 = "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) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
27
Teknik/Areas/User/Models/InviteCode.cs
Normal file
27
Teknik/Areas/User/Models/InviteCode.cs
Normal file
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
Teknik/Areas/User/Scripts/BlogSettings.js
Normal file
29
Teknik/Areas/User/Scripts/BlogSettings.js
Normal file
@ -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;
|
||||
});
|
||||
});
|
35
Teknik/Areas/User/Scripts/InviteSettings.js
Normal file
35
Teknik/Areas/User/Scripts/InviteSettings.js
Normal file
@ -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>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
31
Teknik/Areas/User/Scripts/ProfileSettings.js
Normal file
31
Teknik/Areas/User/Scripts/ProfileSettings.js
Normal file
@ -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;
|
||||
});
|
||||
});
|
49
Teknik/Areas/User/Scripts/ResetPass.js
Normal file
49
Teknik/Areas/User/Scripts/ResetPass.js
Normal file
@ -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>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
22
Teknik/Areas/User/Scripts/Settings.js
Normal file
22
Teknik/Areas/User/Scripts/Settings.js
Normal file
@ -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>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
29
Teknik/Areas/User/Scripts/UploadSettings.js
Normal file
29
Teknik/Areas/User/Scripts/UploadSettings.js
Normal file
@ -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();
|
||||
|
22
Teknik/Areas/User/ViewModels/BlogSettingsViewModel.cs
Normal file
22
Teknik/Areas/User/ViewModels/BlogSettingsViewModel.cs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
21
Teknik/Areas/User/ViewModels/InviteCodeViewModel.cs
Normal file
21
Teknik/Areas/User/ViewModels/InviteCodeViewModel.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
21
Teknik/Areas/User/ViewModels/InviteSettingsViewModel.cs
Normal file
21
Teknik/Areas/User/ViewModels/InviteSettingsViewModel.cs
Normal file
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
27
Teknik/Areas/User/ViewModels/ProfileSettingsViewModel.cs
Normal file
27
Teknik/Areas/User/ViewModels/ProfileSettingsViewModel.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
Teknik/Areas/User/ViewModels/SecuritySettingsViewModel.cs
Normal file
50
Teknik/Areas/User/ViewModels/SecuritySettingsViewModel.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
Teknik/Areas/User/ViewModels/UploadSettingsViewModel.cs
Normal file
19
Teknik/Areas/User/ViewModels/UploadSettingsViewModel.cs
Normal file
@ -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>
|
36
Teknik/Areas/User/Views/User/Settings/BlogSettings.cshtml
Normal file
36
Teknik/Areas/User/Views/User/Settings/BlogSettings.cshtml
Normal file
@ -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>
|
21
Teknik/Areas/User/Views/User/Settings/InviteCode.cshtml
Normal file
21
Teknik/Areas/User/Views/User/Settings/InviteCode.cshtml
Normal file
@ -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>
|
59
Teknik/Areas/User/Views/User/Settings/InviteSettings.cshtml
Normal file
59
Teknik/Areas/User/Views/User/Settings/InviteSettings.cshtml
Normal file
@ -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>
|
41
Teknik/Areas/User/Views/User/Settings/ProfileSettings.cshtml
Normal file
41
Teknik/Areas/User/Views/User/Settings/ProfileSettings.cshtml
Normal file
@ -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>
|
178
Teknik/Areas/User/Views/User/Settings/SecuritySettings.cshtml
Normal file
178
Teknik/Areas/User/Views/User/Settings/SecuritySettings.cshtml
Normal file
@ -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>
|
||||
</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.PgpPublicKey</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.RecoveryEmail" />
|
||||
@if (!string.IsNullOrEmpty(Model.RecoveryEmail))
|
||||
{
|
||||
<p class="form-control-static">
|
||||
@if (Model.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.TwoFactorEnabled ? "checked" : string.Empty) />
|
||||
</label>
|
||||
</div>
|
||||
<p class="form-control-static @(Model.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.AllowTrustedDevices ? "checked" : string.Empty) />
|
||||
</label>
|
||||
</div>
|
||||
<p class="form-control-static @(Model.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("Settings/AuthToken", token)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<li class="list-group-item text-center" id="noAuthTokens">No Authentication Tokens</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</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>
|
51
Teknik/Areas/User/Views/User/Settings/Settings.cshtml
Normal file
51
Teknik/Areas/User/Views/User/Settings/Settings.cshtml
Normal file
@ -0,0 +1,51 @@
|
||||
@model Teknik.Areas.Users.ViewModels.SettingsViewModel
|
||||
|
||||
@{
|
||||
Layout = "~/Views/Shared/_Layout.cshtml";
|
||||
}
|
||||
|
||||
@using Teknik.Utilities
|
||||
@using Teknik.Areas.Users.ViewModels
|
||||
|
||||
@Styles.Render("~/Content/user/settings")
|
||||
@Scripts.Render("~/bundles/user/settings")
|
||||
|
||||
<script>
|
||||
var homeUrl = '@Url.SubRouteUrl("www", "Home.Index")';
|
||||
var deleteUserURL = '@Url.SubRouteUrl("user", "User.Action", new { action = "Delete" })';
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
@if (!Model.Error)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-sm-2">
|
||||
<!--left col-->
|
||||
<div class="panel panel-default">
|
||||
<ul class="list-group">
|
||||
<div class="panel-heading text-center"><strong>Account Settings</strong></div>
|
||||
<a href="@Url.SubRouteUrl("user", "User.SecuritySettings")" class="list-group-item @(Model.Page == "Security" ? "active" : string.Empty)">Security</a>
|
||||
<a href="@Url.SubRouteUrl("user", "User.ProfileSettings")" class="list-group-item @(Model.Page == "Profile" ? "active" : string.Empty)">Profile</a>
|
||||
<a href="@Url.SubRouteUrl("user", "User.InviteSettings")" class="list-group-item @(Model.Page == "Invite" ? "active" : string.Empty)">Invite Codes (@(User.Info.OwnedInviteCodes.Where(c => c.Active).Count()))</a>
|
||||
<a href="@Url.SubRouteUrl("user", "User.BlogSettings")" class="list-group-item @(Model.Page == "Blog" ? "active" : string.Empty)">Blogging</a>
|
||||
<a href="@Url.SubRouteUrl("user", "User.UploadSettings")" class="list-group-item @(Model.Page == "Upload" ? "active" : string.Empty)">Uploads</a>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="list-group text-center">
|
||||
<button type="button" class="list-group-item btn-danger" id="delete_account">Delete Account</button>
|
||||
</div>
|
||||
</div><!--/col-2-->
|
||||
<div class="col-sm-10">
|
||||
@RenderBody()
|
||||
</div><!--/col-10-->
|
||||
</div><!--/row-->
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<h2>@Model.ErrorMessage</h2>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
12
Teknik/Areas/User/Views/User/Settings/SettingsBase.cshtml
Normal file
12
Teknik/Areas/User/Views/User/Settings/SettingsBase.cshtml
Normal file
@ -0,0 +1,12 @@
|
||||
@model Teknik.Areas.Users.ViewModels.SettingsViewModel
|
||||
|
||||
@{
|
||||
Layout = "~/Areas/User/Views/User/Settings/Settings.cshtml";
|
||||
}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-10 col-sm-offset-1">
|
||||
<p>Default Account Settings</p>
|
||||
</div>
|
||||
</div>
|
||||
|
36
Teknik/Areas/User/Views/User/Settings/UploadSettings.cshtml
Normal file
36
Teknik/Areas/User/Views/User/Settings/UploadSettings.cshtml
Normal file
@ -0,0 +1,36 @@
|
||||
@model Teknik.Areas.Users.ViewModels.UploadSettingsViewModel
|
||||
|
||||
@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 = "EditUpload" })';
|
||||
</script>
|
||||
|
||||
@Styles.Render("~/Content/user/settings/upload")
|
||||
@Scripts.Render("~/bundles/user/settings/upload")
|
||||
|
||||
<form class="form" action="##" method="post" id="updateForm">
|
||||
<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.Encrypt ? "checked" : string.Empty) />
|
||||
</label>
|
||||
</div>
|
||||
</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>
|
@ -1,11 +1,11 @@
|
||||
@model Teknik.ViewModels.ViewModelBase
|
||||
@model Teknik.ViewModels.ViewModelBase
|
||||
|
||||
@using Teknik.Utilities
|
||||
@using Microsoft.AspNet.Identity
|
||||
|
||||
@if (Model.Config.UserConfig.RegistrationEnabled || Model.Config.UserConfig.LoginEnabled)
|
||||
{
|
||||
<div class="nav navbar-nav pull-right">
|
||||
<div class="nav navbar-nav pull-right">
|
||||
@if (Request.IsAuthenticated)
|
||||
{
|
||||
<li class="dropdown">
|
||||
@ -22,9 +22,9 @@
|
||||
</li>
|
||||
@if (User.IsInRole("Admin"))
|
||||
{
|
||||
<li>
|
||||
<a href="@Url.SubRouteUrl("admin", "Admin.Dashboard")">Administration</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="@Url.SubRouteUrl("admin", "Admin.Dashboard")">Administration</a>
|
||||
</li>
|
||||
}
|
||||
<li>
|
||||
<a href="@Url.SubRouteUrl("user", "User.Logout")">Sign Out</a>
|
||||
@ -49,5 +49,5 @@
|
||||
</noscript>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using Microsoft.AspNet.Identity.EntityFramework;
|
||||
using Microsoft.AspNet.Identity.EntityFramework;
|
||||
using System.Data.Entity;
|
||||
using System.Data.Entity.Infrastructure;
|
||||
using Teknik.Areas.Blog.Models;
|
||||
@ -26,6 +26,7 @@ namespace Teknik.Models
|
||||
public DbSet<TrustedDevice> TrustedDevices { get; set; }
|
||||
public DbSet<AuthToken> AuthTokens { get; set; }
|
||||
public DbSet<TransferType> TransferTypes { get; set; }
|
||||
public DbSet<InviteCode> InviteCodes { get; set; }
|
||||
// User Settings
|
||||
public DbSet<UserSettings> UserSettings { get; set; }
|
||||
public DbSet<SecuritySettings> SecuritySettings { get; set; }
|
||||
@ -115,6 +116,16 @@ namespace Teknik.Models
|
||||
.WithOptional(u => u.User)
|
||||
.WillCascadeOnDelete(false);
|
||||
|
||||
modelBuilder.Entity<User>()
|
||||
.HasMany(u => u.OwnedInviteCodes)
|
||||
.WithOptional(c => c.Owner)
|
||||
.WillCascadeOnDelete(false);
|
||||
|
||||
modelBuilder.Entity<User>()
|
||||
.HasOptional(u => u.ClaimedInviteCode)
|
||||
.WithOptionalPrincipal(c => c.ClaimedUser)
|
||||
.WillCascadeOnDelete(false);
|
||||
|
||||
// Upload Mappings
|
||||
modelBuilder.Entity<Upload>()
|
||||
.HasOptional(u => u.User);
|
||||
@ -130,13 +141,14 @@ namespace Teknik.Models
|
||||
// Vault Mappings
|
||||
modelBuilder.Entity<Vault>()
|
||||
.HasOptional(u => u.User);
|
||||
|
||||
|
||||
// Users
|
||||
modelBuilder.Entity<User>().ToTable("Users");
|
||||
modelBuilder.Entity<Group>().ToTable("Groups");
|
||||
modelBuilder.Entity<Role>().ToTable("Roles");
|
||||
modelBuilder.Entity<TrustedDevice>().ToTable("TrustedDevices");
|
||||
modelBuilder.Entity<AuthToken>().ToTable("AuthTokens");
|
||||
modelBuilder.Entity<InviteCode>().ToTable("InviteCodes");
|
||||
modelBuilder.Entity<TransferType>().ToTable("TransferTypes");
|
||||
modelBuilder.Entity<RecoveryEmailVerification>().ToTable("RecoveryEmailVerifications");
|
||||
modelBuilder.Entity<ResetPasswordVerification>().ToTable("ResetPasswordVerifications");
|
||||
@ -176,4 +188,4 @@ namespace Teknik.Models
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
$(document).ready(function () {
|
||||
$(document).ready(function () {
|
||||
$("#top_msg").css('display', 'none', 'important');
|
||||
|
||||
// Opt-in for tooltips
|
||||
@ -280,6 +280,41 @@ function addParamsToUrl(origUrl, params) {
|
||||
var appendix = (hasQuery ? "&" : "?") + paramStr;
|
||||
return hasHash ? origUrl.replace("#", appendix + "#") : origUrl + appendix;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function parseErrorMessage(errorObj) {
|
||||
var errorMsg = "";
|
||||
if (errorObj === null || errorObj === undefined) {
|
||||
// Do nothing
|
||||
}
|
||||
else if (errorObj.constructor === {}.constructor) {
|
||||
if (errorObj.error) {
|
||||
errorMsg = errorObj.error;
|
||||
if (errorObj.error.message) {
|
||||
errorMsg = errorObj.error.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
var json = $.parseJSON(errorObj);
|
||||
if (json.error) {
|
||||
errorMsg = json.error;
|
||||
if (json.error.message) {
|
||||
errorMsg = json.error.message;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
// Don't do anything
|
||||
}
|
||||
}
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
/***************************** TIMER Page Load *******************************/
|
||||
var loopTime;
|
||||
var startTime = new Date();
|
||||
@ -301,4 +336,4 @@ function pageloadStopTimer() {
|
||||
$('#pagetime').show();
|
||||
|
||||
clearTimeout(loopTime);
|
||||
}
|
||||
}
|
||||
|
@ -293,15 +293,22 @@
|
||||
<Compile Include="Areas\Status\ViewModels\TransactionViewModel.cs" />
|
||||
<Compile Include="Areas\User\Controllers\UserController.cs" />
|
||||
<Compile Include="Areas\User\Models\BlogSettings.cs" />
|
||||
<Compile Include="Areas\User\Models\InviteCode.cs" />
|
||||
<Compile Include="Areas\User\Models\ResetPasswordVerification.cs" />
|
||||
<Compile Include="Areas\User\Models\RecoveryEmailVerification.cs" />
|
||||
<Compile Include="Areas\User\Models\SecuritySettings.cs" />
|
||||
<Compile Include="Areas\User\Models\AuthToken.cs" />
|
||||
<Compile Include="Areas\User\Models\TrustedDevice.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\AuthTokenViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\InviteCodeViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\InviteSettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\UploadSettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\EditSettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\GetPremiumViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\BlogSettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\SecuritySettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\SetPasswordViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\ProfileSettingsViewModel.cs" />
|
||||
<Compile Include="Areas\User\ViewModels\TwoFactorViewModel.cs" />
|
||||
<Compile Include="Areas\Vault\ViewModels\ModifyVaultViewModel.cs" />
|
||||
<Compile Include="Areas\Vault\ViewModels\ModifyVaultItemViewModel.cs" />
|
||||
@ -410,7 +417,13 @@
|
||||
<Content Include="Areas\Upload\Content\Upload.css" />
|
||||
<Content Include="Areas\User\Scripts\CheckAuthCode.js" />
|
||||
<Content Include="Areas\User\Scripts\Profile.js" />
|
||||
<Content Include="Areas\User\Scripts\User.js" />
|
||||
<Content Include="Areas\User\Scripts\Settings.js" />
|
||||
<Content Include="Areas\User\Scripts\BlogSettings.js" />
|
||||
<Content Include="Areas\User\Scripts\InviteSettings.js" />
|
||||
<Content Include="Areas\User\Scripts\ProfileSettings.js" />
|
||||
<Content Include="Areas\User\Scripts\SecuritySettings.js" />
|
||||
<Content Include="Areas\User\Scripts\UploadSettings.js" />
|
||||
<Content Include="Areas\User\Scripts\ResetPass.js" />
|
||||
<Content Include="Areas\Shortener\Scripts\Shortener.js" />
|
||||
<Content Include="Areas\Upload\Scripts\Download.js" />
|
||||
<Content Include="Areas\Vault\Content\Vault.css" />
|
||||
@ -598,7 +611,7 @@
|
||||
<Content Include="Areas\Podcast\Views\Podcast\Comments.cshtml" />
|
||||
<Content Include="Areas\Podcast\Views\Podcast\ViewPodcast.cshtml" />
|
||||
<Content Include="App_Data\Config.json" />
|
||||
<Content Include="Areas\User\Views\User\Settings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\Settings.cshtml" />
|
||||
<Content Include="Areas\Vault\Views\_ViewStart.cshtml" />
|
||||
<Content Include="Areas\Help\Views\Help\RSS.cshtml" />
|
||||
<Content Include="Areas\Stream\Views\web.config" />
|
||||
@ -643,7 +656,7 @@
|
||||
<Content Include="Fonts\fontawesome-webfont.woff" />
|
||||
<Content Include="Fonts\fontawesome-webfont.ttf" />
|
||||
<Content Include="Fonts\fontawesome-webfont.eot" />
|
||||
<Content Include="Areas\User\Views\User\AuthToken.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\AuthToken.cshtml" />
|
||||
<Content Include="Areas\Error\Views\Error\Http401.cshtml" />
|
||||
<Content Include="Areas\Vault\Views\Vault\ModifyVault.cshtml" />
|
||||
<Content Include="Areas\Vault\Views\Vault\ModifyVaultItem.cshtml" />
|
||||
@ -666,6 +679,13 @@
|
||||
<Content Include="Areas\IRC\Views\web.config" />
|
||||
<Content Include="Areas\IRC\Views\IRC\Client.cshtml" />
|
||||
<Content Include="Areas\IRC\Views\_ViewStart.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\ProfileSettings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\SecuritySettings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\InviteSettings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\BlogSettings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\UploadSettings.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\SettingsBase.cshtml" />
|
||||
<Content Include="Areas\User\Views\User\Settings\InviteCode.cshtml" />
|
||||
<None Include="Properties\PublishProfiles\Teknik Dev.pubxml" />
|
||||
<None Include="Properties\PublishProfiles\Teknik Production.pubxml" />
|
||||
<None Include="Scripts\jquery-2.1.4.intellisense.js" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -19,6 +19,7 @@ namespace Teknik.Configuration
|
||||
public string ReservedUsernameDefinitionFile { get; set; }
|
||||
public decimal PremiumAccountPrice { get; set; }
|
||||
public string PaymentType { get; set; }
|
||||
public bool InviteCodeRequired { get; set; }
|
||||
|
||||
public UserConfig()
|
||||
{
|
||||
@ -32,6 +33,7 @@ namespace Teknik.Configuration
|
||||
ReservedUsernameDefinitionFile = string.Empty;
|
||||
PremiumAccountPrice = 0;
|
||||
PaymentType = "Donation";
|
||||
InviteCodeRequired = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user