notification service and user management improvements
This commit is contained in:
108
Oqtane.Server/Controllers/FolderController.cs
Normal file
108
Oqtane.Server/Controllers/FolderController.cs
Normal file
@ -0,0 +1,108 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using System.Linq;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Security;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route("{site}/api/[controller]")]
|
||||
public class FolderController : Controller
|
||||
{
|
||||
private readonly IFolderRepository Folders;
|
||||
private readonly IUserPermissions UserPermissions;
|
||||
private readonly ILogManager logger;
|
||||
|
||||
public FolderController(IFolderRepository Folders, IUserPermissions UserPermissions, ILogManager logger)
|
||||
{
|
||||
this.Folders = Folders;
|
||||
this.UserPermissions = UserPermissions;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x
|
||||
[HttpGet]
|
||||
public IEnumerable<Folder> Get(string siteid)
|
||||
{
|
||||
if (siteid == "")
|
||||
{
|
||||
return Folders.GetFolders();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Folders.GetFolders(int.Parse(siteid));
|
||||
}
|
||||
}
|
||||
|
||||
// GET api/<controller>/5?userid=x
|
||||
[HttpGet("{id}")]
|
||||
public Folder Get(int id)
|
||||
{
|
||||
return Folders.GetFolder(id);
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public Folder Post([FromBody] Folder Folder)
|
||||
{
|
||||
if (ModelState.IsValid && UserPermissions.IsAuthorized(User, "Edit", Folder.Permissions))
|
||||
{
|
||||
Folder = Folders.AddFolder(Folder);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", Folder);
|
||||
}
|
||||
return Folder;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public Folder Put(int id, [FromBody] Folder Folder)
|
||||
{
|
||||
if (ModelState.IsValid && UserPermissions.IsAuthorized(User, "Folder", Folder.FolderId, "Edit"))
|
||||
{
|
||||
Folder = Folders.UpdateFolder(Folder);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", Folder);
|
||||
}
|
||||
return Folder;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/?siteid=x&folderid=y&parentid=z
|
||||
[HttpPut]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public void Put(int siteid, int folderid, int? parentid)
|
||||
{
|
||||
if (UserPermissions.IsAuthorized(User, "Folder", folderid, "Edit"))
|
||||
{
|
||||
int order = 1;
|
||||
List<Folder> folders = Folders.GetFolders(siteid).ToList();
|
||||
foreach (Folder folder in folders.Where(item => item.ParentId == parentid).OrderBy(item => item.Order))
|
||||
{
|
||||
if (folder.Order != order)
|
||||
{
|
||||
folder.Order = order;
|
||||
Folders.UpdateFolder(folder);
|
||||
}
|
||||
order += 2;
|
||||
}
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Order Updated {SiteId} {FolderId} {ParentId}", siteid, folderid, parentid);
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
if (UserPermissions.IsAuthorized(User, "Folder", id, "Edit"))
|
||||
{
|
||||
Folders.DeleteFolder(id);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Delete, "Folder Deleted {FolderId}", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
110
Oqtane.Server/Controllers/NotificationController.cs
Normal file
110
Oqtane.Server/Controllers/NotificationController.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route("{site}/api/[controller]")]
|
||||
public class NotificationController : Controller
|
||||
{
|
||||
private readonly INotificationRepository Notifications;
|
||||
private readonly IHttpContextAccessor Accessor;
|
||||
private readonly ILogManager logger;
|
||||
|
||||
public NotificationController(INotificationRepository Notifications, IHttpContextAccessor Accessor, ILogManager logger)
|
||||
{
|
||||
this.Notifications = Notifications;
|
||||
this.Accessor = Accessor;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
// GET: api/<controller>?siteid=x&type=y&userid=z
|
||||
[HttpGet]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public IEnumerable<Notification> Get(string siteid, string direction, string userid)
|
||||
{
|
||||
IEnumerable<Notification> notifications = null;
|
||||
if (IsAuthorized(int.Parse(userid)))
|
||||
{
|
||||
if (direction == "to")
|
||||
{
|
||||
notifications = Notifications.GetNotifications(int.Parse(siteid), -1, int.Parse(userid));
|
||||
}
|
||||
else
|
||||
{
|
||||
notifications = Notifications.GetNotifications(int.Parse(siteid), int.Parse(userid), -1);
|
||||
}
|
||||
}
|
||||
return notifications;
|
||||
}
|
||||
|
||||
// GET api/<controller>/5
|
||||
[HttpGet("{id}")]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public Notification Get(int id)
|
||||
{
|
||||
Notification Notification = Notifications.GetNotification(id);
|
||||
if (!(IsAuthorized(Notification.FromUserId) || IsAuthorized(Notification.ToUserId)))
|
||||
{
|
||||
Notification = null;
|
||||
}
|
||||
return Notification;
|
||||
}
|
||||
|
||||
// POST api/<controller>
|
||||
[HttpPost]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public Notification Post([FromBody] Notification Notification)
|
||||
{
|
||||
if (IsAuthorized(Notification.FromUserId))
|
||||
{
|
||||
Notification = Notifications.AddNotification(Notification);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {Notification}", Notification);
|
||||
}
|
||||
return Notification;
|
||||
}
|
||||
|
||||
// PUT api/<controller>/5
|
||||
[HttpPut("{id}")]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public Notification Put(int id, [FromBody] Notification Notification)
|
||||
{
|
||||
if (IsAuthorized(Notification.FromUserId))
|
||||
{
|
||||
Notification = Notifications.UpdateNotification(Notification);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {Folder}", Notification);
|
||||
}
|
||||
return Notification;
|
||||
}
|
||||
|
||||
// DELETE api/<controller>/5
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Roles = Constants.RegisteredRole)]
|
||||
public void Delete(int id)
|
||||
{
|
||||
Notification Notification = Notifications.GetNotification(id);
|
||||
if (IsAuthorized(Notification.FromUserId) || IsAuthorized(Notification.ToUserId))
|
||||
{
|
||||
Notifications.DeleteNotification(id);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Delete, "Notification Deleted {NotificationId}", id);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAuthorized(int? userid)
|
||||
{
|
||||
bool authorized = true;
|
||||
if (userid != null)
|
||||
{
|
||||
authorized = (int.Parse(Accessor.HttpContext.User.FindFirst(ClaimTypes.PrimarySid).Value) == userid);
|
||||
}
|
||||
return authorized;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -10,6 +10,9 @@ using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Infrastructure;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Net;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -21,15 +24,19 @@ namespace Oqtane.Controllers
|
||||
private readonly IUserRoleRepository UserRoles;
|
||||
private readonly UserManager<IdentityUser> IdentityUserManager;
|
||||
private readonly SignInManager<IdentityUser> IdentitySignInManager;
|
||||
private readonly ITenantResolver Tenants;
|
||||
private readonly INotificationRepository Notifications;
|
||||
private readonly ILogManager logger;
|
||||
|
||||
public UserController(IUserRepository Users, IRoleRepository Roles, IUserRoleRepository UserRoles, UserManager<IdentityUser> IdentityUserManager, SignInManager<IdentityUser> IdentitySignInManager, ILogManager logger)
|
||||
public UserController(IUserRepository Users, IRoleRepository Roles, IUserRoleRepository UserRoles, UserManager<IdentityUser> IdentityUserManager, SignInManager<IdentityUser> IdentitySignInManager, ITenantResolver Tenants, INotificationRepository Notifications, ILogManager logger)
|
||||
{
|
||||
this.Users = Users;
|
||||
this.Roles = Roles;
|
||||
this.UserRoles = UserRoles;
|
||||
this.IdentityUserManager = IdentityUserManager;
|
||||
this.IdentitySignInManager = IdentitySignInManager;
|
||||
this.Tenants = Tenants;
|
||||
this.Notifications = Notifications;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@ -74,10 +81,11 @@ namespace Oqtane.Controllers
|
||||
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
int hostroleid = -1;
|
||||
if (!Users.GetUsers().Any())
|
||||
bool verified = true;
|
||||
// users created by non-administrators must be verified
|
||||
if (!base.User.IsInRole(Constants.AdminRole) && User.Username != Constants.HostUser)
|
||||
{
|
||||
hostroleid = Roles.GetRoles(User.SiteId, true).Where(item => item.Name == Constants.HostRole).FirstOrDefault().RoleId;
|
||||
verified = false;
|
||||
}
|
||||
|
||||
IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username);
|
||||
@ -86,14 +94,34 @@ namespace Oqtane.Controllers
|
||||
identityuser = new IdentityUser();
|
||||
identityuser.UserName = User.Username;
|
||||
identityuser.Email = User.Email;
|
||||
identityuser.EmailConfirmed = verified;
|
||||
var result = await IdentityUserManager.CreateAsync(identityuser, User.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
user = Users.AddUser(User);
|
||||
|
||||
// assign to host role if this is the initial installation
|
||||
if (hostroleid != -1)
|
||||
if (!verified)
|
||||
{
|
||||
Notification notification = new Notification();
|
||||
notification.SiteId = User.SiteId;
|
||||
notification.FromUserId = null;
|
||||
notification.ToUserId = user.UserId;
|
||||
notification.ToEmail = "";
|
||||
notification.Subject = "User Account Verification";
|
||||
string token = await IdentityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string alias = Tenants.GetAlias().Path;
|
||||
string url = HttpContext.Request.Scheme + "://" + HttpContext.Request.Host + "/pages/verify?name=" + User.Username + "&token=" + WebUtility.UrlEncode(token) + "&returnurl=" + (alias == "" ? "/" : alias);
|
||||
notification.Body = "Dear " + User.DisplayName + ",\n\nIn Order To Complete The Registration Of Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
notification.ParentId = null;
|
||||
notification.CreatedOn = DateTime.Now;
|
||||
notification.IsDelivered = false;
|
||||
notification.DeliveredOn = null;
|
||||
Notifications.AddNotification(notification);
|
||||
}
|
||||
|
||||
// assign to host role if this is the host user ( initial installation )
|
||||
if (User.Username == Constants.HostUser)
|
||||
{
|
||||
int hostroleid = Roles.GetRoles(User.SiteId, true).Where(item => item.Name == Constants.HostRole).FirstOrDefault().RoleId;
|
||||
UserRole userrole = new UserRole();
|
||||
userrole.UserId = user.UserId;
|
||||
userrole.RoleId = hostroleid;
|
||||
@ -112,7 +140,7 @@ namespace Oqtane.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
if (user != null && hostroleid == -1)
|
||||
if (user != null && User.Username != Constants.HostUser)
|
||||
{
|
||||
// add auto assigned roles to user for site
|
||||
List<Role> roles = Roles.GetRoles(User.SiteId).Where(item => item.IsAutoAssigned == true).ToList();
|
||||
@ -192,11 +220,18 @@ namespace Oqtane.Controllers
|
||||
user = Users.GetUser(identityuser.UserName);
|
||||
if (user != null)
|
||||
{
|
||||
user.IsAuthenticated = true;
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Successful {Username}", User.Username);
|
||||
if (SetCookie)
|
||||
if (identityuser.EmailConfirmed)
|
||||
{
|
||||
await IdentitySignInManager.SignInAsync(identityuser, IsPersistent);
|
||||
user.IsAuthenticated = true;
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "User Login Successful {Username}", User.Username);
|
||||
if (SetCookie)
|
||||
{
|
||||
await IdentitySignInManager.SignInAsync(identityuser, IsPersistent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "User Not Verified {Username}", User.Username);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,6 +254,68 @@ namespace Oqtane.Controllers
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout {Username}", User.Username);
|
||||
}
|
||||
|
||||
// POST api/<controller>/forgot
|
||||
[HttpPost("forgot")]
|
||||
public async Task Forgot([FromBody] User User)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
Notification notification = new Notification();
|
||||
notification.SiteId = User.SiteId;
|
||||
notification.FromUserId = null;
|
||||
notification.ToUserId = User.UserId;
|
||||
notification.ToEmail = "";
|
||||
notification.Subject = "User Password Reset";
|
||||
string token = await IdentityUserManager.GeneratePasswordResetTokenAsync(identityuser);
|
||||
string url = HttpContext.Request.Scheme + "://" + Tenants.GetAlias().Name + "/reset?name=" + User.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
notification.Body = "Dear " + User.DisplayName + ",\n\nPlease Click The Link Displayed Below To Reset Your Password:\n\n" + url + "\n\nThank You!";
|
||||
notification.ParentId = null;
|
||||
notification.CreatedOn = DateTime.Now;
|
||||
notification.IsDelivered = false;
|
||||
notification.DeliveredOn = null;
|
||||
Notifications.AddNotification(notification);
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset Notification Sent For {Username}", User.Username);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Notification Failed For {Username}", User.Username);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// POST api/<controller>/reset
|
||||
[HttpPost("reset")]
|
||||
public async Task<User> Reset([FromBody] User User, string token)
|
||||
{
|
||||
User user = null;
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(User.Username);
|
||||
if (identityuser != null && !string.IsNullOrEmpty(token))
|
||||
{
|
||||
var result = await IdentityUserManager.ResetPasswordAsync(identityuser, token, User.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
user = User;
|
||||
user.Password = "";
|
||||
logger.Log(LogLevel.Information, this, LogFunction.Security, "Password Reset For {Username}", User.Username);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", User.Username);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Log(LogLevel.Error, this, LogFunction.Security, "Password Reset Failed For {Username}", User.Username);
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
// GET api/<controller>/current
|
||||
[HttpGet("authenticate")]
|
||||
public User Authenticate()
|
||||
|
130
Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs
Normal file
130
Oqtane.Server/Infrastructure/Jobs/NotificationJob.cs
Normal file
@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class NotificationJob : HostedServiceBase
|
||||
{
|
||||
// JobType = "Oqtane.Infrastructure.NotificationJob, Oqtane.Server"
|
||||
|
||||
public NotificationJob(IServiceScopeFactory ServiceScopeFactory) : base(ServiceScopeFactory) {}
|
||||
|
||||
public override string ExecuteJob(IServiceProvider provider)
|
||||
{
|
||||
string log = "";
|
||||
|
||||
// iterate through aliases in this installation
|
||||
var Aliases = provider.GetRequiredService<IAliasRepository>();
|
||||
List<Alias> aliases = Aliases.GetAliases().ToList();
|
||||
foreach (Alias alias in aliases)
|
||||
{
|
||||
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
||||
var sitestate = provider.GetRequiredService<SiteState>();
|
||||
sitestate.Alias = alias;
|
||||
|
||||
// get services which require tenant resolution
|
||||
var Sites = provider.GetRequiredService<ISiteRepository>();
|
||||
var Settings = provider.GetRequiredService<ISettingRepository>();
|
||||
var Notifications = provider.GetRequiredService<INotificationRepository>();
|
||||
|
||||
// iterate through sites
|
||||
List<Site> sites = Sites.GetSites().ToList();
|
||||
foreach (Site site in sites)
|
||||
{
|
||||
log += "Processing Notifications For Site: " + site.Name + "\n\n";
|
||||
|
||||
// get site settings
|
||||
List<Setting> sitesettings = Settings.GetSettings("Site", site.SiteId).ToList();
|
||||
Dictionary<string, string> settings = GetSettings(sitesettings);
|
||||
if (settings.ContainsKey("SMTPHost") && settings["SMTPHost"] != "")
|
||||
{
|
||||
// construct SMTP Client
|
||||
var client = new SmtpClient()
|
||||
{
|
||||
DeliveryMethod = SmtpDeliveryMethod.Network,
|
||||
UseDefaultCredentials = false,
|
||||
Host = settings["SMTPHost"],
|
||||
Port = int.Parse(settings["SMTPPort"]),
|
||||
EnableSsl = bool.Parse(settings["SMTPSSL"])
|
||||
};
|
||||
if (settings["SMTPUsername"] != "" && settings["SMTPPassword"] != "")
|
||||
{
|
||||
client.Credentials = new NetworkCredential(settings["SMTPUsername"], settings["SMTPPassword"]);
|
||||
}
|
||||
|
||||
// iterate through notifications
|
||||
int sent = 0;
|
||||
List<Notification> notifications = Notifications.GetNotifications(site.SiteId, -1, -1).ToList();
|
||||
foreach (Notification notification in notifications)
|
||||
{
|
||||
MailMessage mailMessage = new MailMessage();
|
||||
mailMessage.From = new MailAddress(settings["SMTPUsername"], site.Name);
|
||||
|
||||
if (notification.FromUserId != null)
|
||||
{
|
||||
mailMessage.Body = "From: " + notification.FromUser.DisplayName + "<" + notification.FromUser.Email + ">" + "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.Body = "From: " + site.Name + "\n";
|
||||
}
|
||||
mailMessage.Body += "Sent: " + notification.CreatedOn.ToString() + "\n";
|
||||
if (notification.ToUserId != null)
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToUser.Email, notification.ToUser.DisplayName));
|
||||
mailMessage.Body += "To: " + notification.ToUser.DisplayName + "<" + notification.ToUser.Email + ">" + "\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
mailMessage.To.Add(new MailAddress(notification.ToEmail));
|
||||
mailMessage.Body += "To: " + notification.ToEmail + "\n";
|
||||
}
|
||||
mailMessage.Body += "Subject: " + notification.Subject + "\n\n";
|
||||
mailMessage.Body += notification.Body;
|
||||
|
||||
// send mail
|
||||
try
|
||||
{
|
||||
client.Send(mailMessage);
|
||||
sent = sent++;
|
||||
notification.IsDelivered = true;
|
||||
notification.DeliveredOn = DateTime.Now;
|
||||
Notifications.UpdateNotification(notification);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// error
|
||||
log += ex.Message.ToString() + "\n\n";
|
||||
}
|
||||
}
|
||||
log += "Notifications Delivered: " + sent.ToString() + "\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
log += "SMTP Not Configured" + "\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<string, string> GetSettings(List<Setting> Settings)
|
||||
{
|
||||
Dictionary<string, string> dictionary = new Dictionary<string, string>();
|
||||
foreach (Setting setting in Settings.OrderBy(item => item.SettingName).ToList())
|
||||
{
|
||||
dictionary.Add(setting.SettingName, setting.SettingValue);
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class SampleJob : HostedServiceBase
|
||||
{
|
||||
// JobType = "Oqtane.Infrastructure.SampleJob, Oqtane.Server"
|
||||
|
||||
public SampleJob(IServiceScopeFactory ServiceScopeFactory) : base(ServiceScopeFactory) {}
|
||||
|
||||
public override string ExecuteJob(IServiceProvider provider)
|
||||
{
|
||||
// get the first alias for this installation
|
||||
var Aliases = provider.GetRequiredService<IAliasRepository>();
|
||||
Alias alias = Aliases.GetAliases().FirstOrDefault();
|
||||
|
||||
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
||||
var sitestate = provider.GetRequiredService<SiteState>();
|
||||
sitestate.Alias = alias;
|
||||
|
||||
// call a repository service which requires tenant resolution
|
||||
var Sites = provider.GetRequiredService<ISiteRepository>();
|
||||
Site site = Sites.GetSites().FirstOrDefault();
|
||||
|
||||
return "You Should Include Any Notes Related To The Execution Of The Schedule Job. This Job Simply Reports That The Default Site Is " + site.Name;
|
||||
}
|
||||
}
|
||||
}
|
@ -41,8 +41,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Blazor.Server" Version="3.1.0-preview4.19579.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
@page "/login"
|
||||
@page "/pages/login"
|
||||
@namespace Oqtane.Pages
|
||||
@model Oqtane.Pages.LoginModel
|
||||
|
@ -1,3 +1,3 @@
|
||||
@page "/logout"
|
||||
@page "/pages/logout"
|
||||
@namespace Oqtane.Pages
|
||||
@model Oqtane.Pages.LogoutModel
|
||||
|
3
Oqtane.Server/Pages/Verify.cshtml
Normal file
3
Oqtane.Server/Pages/Verify.cshtml
Normal file
@ -0,0 +1,3 @@
|
||||
@page "/pages/verify"
|
||||
@namespace Oqtane.Pages
|
||||
@model Oqtane.Pages.VerifyModel
|
42
Oqtane.Server/Pages/Verify.cshtml.cs
Normal file
42
Oqtane.Server/Pages/Verify.cshtml.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Oqtane.Pages
|
||||
{
|
||||
[AllowAnonymous]
|
||||
public class VerifyModel : PageModel
|
||||
{
|
||||
private readonly IUserRepository Users;
|
||||
private readonly UserManager<IdentityUser> IdentityUserManager;
|
||||
|
||||
public VerifyModel(IUserRepository Users, UserManager<IdentityUser> IdentityUserManager)
|
||||
{
|
||||
this.Users = Users;
|
||||
this.IdentityUserManager = IdentityUserManager;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> OnGet(string name, string token, string returnurl)
|
||||
{
|
||||
int verified = 0;
|
||||
IdentityUser identityuser = await IdentityUserManager.FindByNameAsync(name);
|
||||
if (identityuser != null)
|
||||
{
|
||||
var result = await IdentityUserManager.ConfirmEmailAsync(identityuser, token);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
verified = 1;
|
||||
}
|
||||
}
|
||||
if (!returnurl.StartsWith("/"))
|
||||
{
|
||||
returnurl += "/" + returnurl;
|
||||
}
|
||||
return Redirect(HttpContext.Request.Scheme + "://" + HttpContext.Request.Host + returnurl + "login?verified=" + verified.ToString());
|
||||
}
|
||||
}
|
||||
}
|
@ -17,6 +17,8 @@ namespace Oqtane.Repository
|
||||
public virtual DbSet<Permission> Permission { get; set; }
|
||||
public virtual DbSet<Setting> Setting { get; set; }
|
||||
public virtual DbSet<Log> Log { get; set; }
|
||||
public virtual DbSet<Notification> Notification { get; set; }
|
||||
public virtual DbSet<Folder> Folder { get; set; }
|
||||
|
||||
public TenantDBContext(ITenantResolver TenantResolver, IHttpContextAccessor accessor) : base(TenantResolver, accessor)
|
||||
{
|
||||
|
70
Oqtane.Server/Repository/FolderRepository.cs
Normal file
70
Oqtane.Server/Repository/FolderRepository.cs
Normal file
@ -0,0 +1,70 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public class FolderRepository : IFolderRepository
|
||||
{
|
||||
private TenantDBContext db;
|
||||
private readonly IPermissionRepository Permissions;
|
||||
|
||||
public FolderRepository(TenantDBContext context, IPermissionRepository Permissions)
|
||||
{
|
||||
db = context;
|
||||
this.Permissions = Permissions;
|
||||
}
|
||||
|
||||
public IEnumerable<Folder> GetFolders()
|
||||
{
|
||||
return db.Folder.ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<Folder> GetFolders(int SiteId)
|
||||
{
|
||||
IEnumerable<Permission> permissions = Permissions.GetPermissions(SiteId, "Folder").ToList();
|
||||
IEnumerable<Folder> folders = db.Folder.Where(item => item.SiteId == SiteId);
|
||||
foreach(Folder folder in folders)
|
||||
{
|
||||
folder.Permissions = Permissions.EncodePermissions(folder.FolderId, permissions);
|
||||
}
|
||||
return folders;
|
||||
}
|
||||
|
||||
public Folder AddFolder(Folder Folder)
|
||||
{
|
||||
db.Folder.Add(Folder);
|
||||
db.SaveChanges();
|
||||
Permissions.UpdatePermissions(Folder.SiteId, "Folder", Folder.FolderId, Folder.Permissions);
|
||||
return Folder;
|
||||
}
|
||||
|
||||
public Folder UpdateFolder(Folder Folder)
|
||||
{
|
||||
db.Entry(Folder).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
Permissions.UpdatePermissions(Folder.SiteId, "Folder", Folder.FolderId, Folder.Permissions);
|
||||
return Folder;
|
||||
}
|
||||
|
||||
public Folder GetFolder(int FolderId)
|
||||
{
|
||||
Folder folder = db.Folder.Find(FolderId);
|
||||
if (folder != null)
|
||||
{
|
||||
IEnumerable<Permission> permissions = Permissions.GetPermissions("Folder", folder.FolderId);
|
||||
folder.Permissions = Permissions.EncodePermissions(folder.FolderId, permissions);
|
||||
}
|
||||
return folder;
|
||||
}
|
||||
|
||||
public void DeleteFolder(int FolderId)
|
||||
{
|
||||
Folder Folder = db.Folder.Find(FolderId);
|
||||
Permissions.DeletePermissions(Folder.SiteId, "Folder", FolderId);
|
||||
db.Folder.Remove(Folder);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
15
Oqtane.Server/Repository/Interfaces/IFolderRepository.cs
Normal file
15
Oqtane.Server/Repository/Interfaces/IFolderRepository.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public interface IFolderRepository
|
||||
{
|
||||
IEnumerable<Folder> GetFolders();
|
||||
IEnumerable<Folder> GetFolders(int SiteId);
|
||||
Folder AddFolder(Folder Folder);
|
||||
Folder UpdateFolder(Folder Folder);
|
||||
Folder GetFolder(int FolderId);
|
||||
void DeleteFolder(int FolderId);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public interface INotificationRepository
|
||||
{
|
||||
IEnumerable<Notification> GetNotifications(int SiteId, int FromUserId, int ToUserId);
|
||||
Notification AddNotification(Notification Notification);
|
||||
Notification UpdateNotification(Notification Notification);
|
||||
Notification GetNotification(int NotificationId);
|
||||
void DeleteNotification(int NotificationId);
|
||||
}
|
||||
}
|
67
Oqtane.Server/Repository/NotificationRepository.cs
Normal file
67
Oqtane.Server/Repository/NotificationRepository.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public class NotificationRepository : INotificationRepository
|
||||
{
|
||||
private TenantDBContext db;
|
||||
|
||||
public NotificationRepository(TenantDBContext context)
|
||||
{
|
||||
db = context;
|
||||
}
|
||||
|
||||
public IEnumerable<Notification> GetNotifications(int SiteId, int FromUserId, int ToUserId)
|
||||
{
|
||||
if (ToUserId == -1 && FromUserId == -1)
|
||||
{
|
||||
return db.Notification
|
||||
.Where(item => item.SiteId == SiteId)
|
||||
.Where(item => item.IsDelivered == false)
|
||||
.Include(item => item.FromUser)
|
||||
.Include(item => item.ToUser)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return db.Notification
|
||||
.Where(item => item.SiteId == SiteId)
|
||||
.Where(item => item.ToUserId == ToUserId || ToUserId == -1)
|
||||
.Where(item => item.FromUserId == FromUserId || FromUserId == -1)
|
||||
.Include(item => item.FromUser)
|
||||
.Include(item => item.ToUser)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public Notification AddNotification(Notification Notification)
|
||||
{
|
||||
db.Notification.Add(Notification);
|
||||
db.SaveChanges();
|
||||
return Notification;
|
||||
}
|
||||
|
||||
public Notification UpdateNotification(Notification Notification)
|
||||
{
|
||||
db.Entry(Notification).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
return Notification;
|
||||
}
|
||||
|
||||
public Notification GetNotification(int NotificationId)
|
||||
{
|
||||
return db.Notification.Find(NotificationId);
|
||||
}
|
||||
|
||||
public void DeleteNotification(int NotificationId)
|
||||
{
|
||||
Notification Notification = db.Notification.Find(NotificationId);
|
||||
db.Notification.Remove(Notification);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -104,6 +104,9 @@ namespace Oqtane.Repository
|
||||
SiteTemplate.Add(new PageTemplate { Name = "Register", Parent = "", Path = "register", Icon = "person", IsNavigation = false, IsPersonalizable = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List<PageTemplateModule> {
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Register, Oqtane.Client", Title = "User Registration", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" }
|
||||
}});
|
||||
SiteTemplate.Add(new PageTemplate { Name = "Reset", Parent = "", Path = "reset", Icon = "person", IsNavigation = false, IsPersonalizable = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List<PageTemplateModule> {
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Reset, Oqtane.Client", Title = "Password Reset", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" }
|
||||
}});
|
||||
SiteTemplate.Add(new PageTemplate { Name = "Profile", Parent = "", Path = "profile", Icon = "person", IsNavigation = false, IsPersonalizable = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List<PageTemplateModule> {
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.UserProfile, Oqtane.Client", Title = "User Profile", Pane = "Content", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Content = "" }
|
||||
}});
|
||||
|
@ -23,7 +23,7 @@ namespace Oqtane.Repository
|
||||
return db.UserRole
|
||||
.Include(item => item.Role) // eager load roles
|
||||
.Include(item => item.User) // eager load users
|
||||
.Where(item => item.Role.SiteId == SiteId);
|
||||
.Where(item => item.Role.SiteId == SiteId || item.Role.SiteId == null);
|
||||
}
|
||||
|
||||
public IEnumerable<UserRole> GetUserRoles(int UserId, int SiteId)
|
||||
|
@ -214,7 +214,7 @@ CREATE TABLE [dbo].[Log] (
|
||||
[PageId] [int] NULL,
|
||||
[ModuleId] [int] NULL,
|
||||
[UserId] [int] NULL,
|
||||
[Url] [nvarchar](200) NOT NULL,
|
||||
[Url] [nvarchar](2048) NOT NULL,
|
||||
[Server] [nvarchar](200) NOT NULL,
|
||||
[Category] [nvarchar](200) NOT NULL,
|
||||
[Feature] [nvarchar](200) NOT NULL,
|
||||
@ -232,6 +232,49 @@ CREATE TABLE [dbo].[Log] (
|
||||
)
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[Notification](
|
||||
[NotificationId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[SiteId] [int] NOT NULL,
|
||||
[FromUserId] [int] NULL,
|
||||
[ToUserId] [int] NULL,
|
||||
[ToEmail] [nvarchar](256) NOT NULL,
|
||||
[Subject] [nvarchar](256) NOT NULL,
|
||||
[Body] [nvarchar](max) NOT NULL,
|
||||
[ParentId] [int] NULL,
|
||||
[CreatedOn] [datetime] NOT NULL,
|
||||
[IsDelivered] [bit] NOT NULL,
|
||||
[DeliveredOn] [datetime] NULL,
|
||||
[DeletedBy] [nvarchar](256) NULL,
|
||||
[DeletedOn] [datetime] NULL,
|
||||
[IsDeleted][bit] NOT NULL,
|
||||
CONSTRAINT [PK_Notification] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[NotificationId] ASC
|
||||
)
|
||||
)
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[Folder](
|
||||
[FolderId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[SiteId] [int] NOT NULL,
|
||||
[Path] [nvarchar](50) NOT NULL,
|
||||
[Name] [nvarchar](50) NOT NULL,
|
||||
[ParentId] [int] NULL,
|
||||
[Order] [int] NOT NULL,
|
||||
[CreatedBy] [nvarchar](256) NOT NULL,
|
||||
[CreatedOn] [datetime] NOT NULL,
|
||||
[ModifiedBy] [nvarchar](256) NOT NULL,
|
||||
[ModifiedOn] [datetime] NOT NULL,
|
||||
[DeletedBy] [nvarchar](256) NULL,
|
||||
[DeletedOn] [datetime] NULL,
|
||||
[IsDeleted][bit] NOT NULL,
|
||||
CONSTRAINT [PK_Folder] PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[FolderId] ASC
|
||||
)
|
||||
)
|
||||
GO
|
||||
|
||||
CREATE TABLE [dbo].[HtmlText](
|
||||
[HtmlTextId] [int] IDENTITY(1,1) NOT NULL,
|
||||
[ModuleId] [int] NOT NULL,
|
||||
@ -308,6 +351,16 @@ REFERENCES [dbo].[Site] ([SiteId])
|
||||
ON DELETE CASCADE
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Notification] WITH CHECK ADD CONSTRAINT [FK_Notification_Site] FOREIGN KEY([SiteId])
|
||||
REFERENCES [dbo].[Site] ([SiteId])
|
||||
ON DELETE CASCADE
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[Folder] WITH CHECK ADD CONSTRAINT [FK_Folder_Site] FOREIGN KEY([SiteId])
|
||||
REFERENCES [dbo].[Site] ([SiteId])
|
||||
ON DELETE CASCADE
|
||||
GO
|
||||
|
||||
ALTER TABLE [dbo].[HtmlText] WITH CHECK ADD CONSTRAINT [FK_HtmlText_Module] FOREIGN KEY([ModuleId])
|
||||
REFERENCES [dbo].[Module] ([ModuleId])
|
||||
ON DELETE CASCADE
|
||||
@ -360,3 +413,9 @@ CREATE UNIQUE NONCLUSTERED INDEX IX_UserRole ON dbo.UserRole
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
||||
CREATE UNIQUE NONCLUSTERED INDEX IX_Folder ON dbo.Folder
|
||||
(
|
||||
SiteId,
|
||||
[Path]
|
||||
) ON [PRIMARY]
|
||||
GO
|
||||
|
@ -139,7 +139,7 @@ GO
|
||||
SET IDENTITY_INSERT [dbo].[Job] ON
|
||||
GO
|
||||
INSERT [dbo].[Job] ([JobId], [Name], [JobType], [Frequency], [Interval], [StartDate], [EndDate], [IsEnabled], [IsStarted], [IsExecuting], [NextExecution], [RetentionHistory], [CreatedBy], [CreatedOn], [ModifiedBy], [ModifiedOn])
|
||||
VALUES (1, N'Sample Daily Job', N'Oqtane.Infrastructure.SampleJob, Oqtane.Server', N'd', 1, null, null, 1, 0, 0, null, 10, '', getdate(), '', getdate())
|
||||
VALUES (1, N'Notification Job', N'Oqtane.Infrastructure.NotificationJob, Oqtane.Server', N'm', 1, null, null, 1, 0, 0, null, 10, '', getdate(), '', getdate())
|
||||
GO
|
||||
SET IDENTITY_INSERT [dbo].[Job] OFF
|
||||
GO
|
||||
|
@ -106,6 +106,7 @@ namespace Oqtane.Server
|
||||
services.AddScoped<ILogService, LogService>();
|
||||
services.AddScoped<IJobService, JobService>();
|
||||
services.AddScoped<IJobLogService, JobLogService>();
|
||||
services.AddScoped<INotificationService, NotificationService>();
|
||||
|
||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
|
||||
@ -179,6 +180,7 @@ namespace Oqtane.Server
|
||||
services.AddTransient<ILogManager, LogManager>();
|
||||
services.AddTransient<IJobRepository, JobRepository>();
|
||||
services.AddTransient<IJobLogRepository, JobLogRepository>();
|
||||
services.AddTransient<INotificationRepository, NotificationRepository>();
|
||||
|
||||
services.AddOqtaneModules();
|
||||
services.AddOqtaneThemes();
|
||||
@ -326,6 +328,7 @@ namespace Oqtane.Server
|
||||
services.AddTransient<ILogManager, LogManager>();
|
||||
services.AddTransient<IJobRepository, JobRepository>();
|
||||
services.AddTransient<IJobLogRepository, JobLogRepository>();
|
||||
services.AddTransient<INotificationRepository, NotificationRepository>();
|
||||
|
||||
services.AddOqtaneModules();
|
||||
services.AddOqtaneThemes();
|
||||
|
@ -92,3 +92,21 @@ app {
|
||||
height: 1px;
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.app-link-unstyled, .app-link-unstyled:visited, .app-link-unstyled:hover, .app-link-unstyled:active, .app-link-unstyled:focus, .app-link-unstyled:active:hover {
|
||||
font-style: inherit;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
font-size: inherit;
|
||||
text-decoration: none;
|
||||
font-variant: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
font-family: inherit;
|
||||
border-radius: inherit;
|
||||
border: inherit;
|
||||
outline: inherit;
|
||||
box-shadow: inherit;
|
||||
padding: inherit;
|
||||
vertical-align: inherit;
|
||||
}
|
||||
|
Reference in New Issue
Block a user