increment copyright date to 2022, allow scheduled jobs to support weekly interval, improve dynamic image generation, add defensive logic to router

This commit is contained in:
Shaun Walker 2022-01-05 14:28:42 -05:00
parent eeff4af167
commit 6af5682548
13 changed files with 93 additions and 53 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018-2021 .NET Foundation Copyright (c) 2018-2022 .NET Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -36,6 +36,7 @@
<option value="m">@Localizer["Minute(s)"]</option> <option value="m">@Localizer["Minute(s)"]</option>
<option value="H">@Localizer["Hour(s)"]</option> <option value="H">@Localizer["Hour(s)"]</option>
<option value="d">@Localizer["Day(s)"]</option> <option value="d">@Localizer["Day(s)"]</option>
<option value="w">@Localizer["Week(s)"]</option>
<option value="M">@Localizer["Month(s)"]</option> <option value="M">@Localizer["Month(s)"]</option>
</select> </select>
</div> </div>

View File

@ -95,6 +95,9 @@ else
case "d": case "d":
result += Localizer["Day"]; result += Localizer["Day"];
break; break;
case "w":
result += Localizer["Week"];
break;
case "M": case "M":
result += Localizer["Month"]; result += Localizer["Month"];
break; break;

View File

@ -12,7 +12,7 @@
@if (PageState.User != null && photo != null) @if (PageState.User != null && photo != null)
{ {
<img src="@ImageUrl(photofileid, 400, 400, "crop")" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block"> <img src="@ImageUrl(photofileid, 400, 400)" alt="@displayname" style="max-width: 400px" class="rounded-circle mx-auto d-block">
} }
else else
{ {

View File

@ -134,14 +134,19 @@ namespace Oqtane.Modules
return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment); return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment);
} }
public string ImageUrl(int fileid, int width, int height, string mode) public string ImageUrl(int fileid, int width, int height)
{ {
return ImageUrl(fileid, width, height, mode, 0); return ImageUrl(fileid, width, height, "");
} }
public string ImageUrl(int fileid, int width, int height, string mode, int rotate) public string ImageUrl(int fileid, int width, int height, string mode)
{ {
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate); return ImageUrl(fileid, width, height, mode, "", "", 0, false);
}
public string ImageUrl(int fileid, int width, int height, string mode, string position, string background, int rotate, bool recreate)
{
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
} }
public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "") public virtual Dictionary<string, string> GetUrlParameters(string parametersTemplate = "")

View File

@ -186,4 +186,7 @@
<data name="NextExecution.Text" xml:space="preserve"> <data name="NextExecution.Text" xml:space="preserve">
<value>Next Execution: </value> <value>Next Execution: </value>
</data> </data>
<data name="Week(s)" xml:space="preserve">
<value>Week(s)</value>
</data>
</root> </root>

View File

@ -133,16 +133,16 @@
<value>Every</value> <value>Every</value>
</data> </data>
<data name="Minute" xml:space="preserve"> <data name="Minute" xml:space="preserve">
<value>Minute</value> <value>Minute(s)</value>
</data> </data>
<data name="Hour" xml:space="preserve"> <data name="Hour" xml:space="preserve">
<value>Hour</value> <value>Hour(s)</value>
</data> </data>
<data name="Day" xml:space="preserve"> <data name="Day" xml:space="preserve">
<value>Day</value> <value>Day(s)</value>
</data> </data>
<data name="Month" xml:space="preserve"> <data name="Month" xml:space="preserve">
<value>Month</value> <value>Month(s)</value>
</data> </data>
<data name="Error.Job.Delete" xml:space="preserve"> <data name="Error.Job.Delete" xml:space="preserve">
<value>Error Deleting Job</value> <value>Error Deleting Job</value>
@ -186,4 +186,7 @@
<data name="Message.Job.Stop" xml:space="preserve"> <data name="Message.Job.Stop" xml:space="preserve">
<value>The process responsible for executing this job has been stopped. In order to restart the process you will need to use the Start button or restart the application.</value> <value>The process responsible for executing this job has been stopped. In order to restart the process you will need to use the Start button or restart the application.</value>
</data> </data>
<data name="Week" xml:space="preserve">
<value>Week(s)</value>
</data>
</root> </root>

View File

@ -104,14 +104,19 @@ namespace Oqtane.Themes
return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment); return Utilities.ContentUrl(PageState.Alias, fileid, asAttachment);
} }
public string ImageUrl(int fileid, int width, int height, string mode) public string ImageUrl(int fileid, int width, int height)
{ {
return ImageUrl(fileid, width, height, mode, 0); return ImageUrl(fileid, width, height, "");
} }
public string ImageUrl(int fileid, int width, int height, string mode, int rotate) public string ImageUrl(int fileid, int width, int height, string mode)
{ {
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, rotate); return ImageUrl(fileid, width, height, mode, "", "", 0, false);
}
public string ImageUrl(int fileid, int width, int height, string mode, string position, string background, int rotate, bool recreate)
{
return Utilities.ImageUrl(PageState.Alias, fileid, width, height, mode, position, background, rotate, recreate);
} }
} }
} }

View File

@ -140,9 +140,12 @@
if (authState.User.Identity.IsAuthenticated) if (authState.User.Identity.IsAuthenticated)
{ {
user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId); user = await UserService.GetUserAsync(authState.User.Identity.Name, site.SiteId);
if (user != null)
{
user.IsAuthenticated = authState.User.Identity.IsAuthenticated; user.IsAuthenticated = authState.User.Identity.IsAuthenticated;
} }
} }
}
else else
{ {
user = PageState.User; user = PageState.User;

View File

@ -508,8 +508,8 @@ namespace Oqtane.Controllers
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null; return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
} }
[HttpGet("image/{id}/{width}/{height}/{mode?}/{rotate?}")] [HttpGet("image/{id}/{width}/{height}/{mode}/{position}/{background}/{rotate}/{recreate}")]
public IActionResult GetImage(int id, int width, int height, string mode, string rotate) public IActionResult GetImage(int id, int width, int height, string mode, string position, string background, string rotate, string recreate)
{ {
var file = _files.GetFile(id); var file = _files.GetFile(id);
if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions)) if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, PermissionNames.View, file.Folder.Permissions))
@ -519,21 +519,25 @@ namespace Oqtane.Controllers
var filepath = _files.GetFilePath(file); var filepath = _files.GetFilePath(file);
if (System.IO.File.Exists(filepath)) if (System.IO.File.Exists(filepath))
{ {
mode = (string.IsNullOrEmpty(mode)) ? "crop" : mode; // validation
rotate = (string.IsNullOrEmpty(rotate)) ? "0" : rotate; if (!Enum.TryParse(mode, true, out ResizeMode _)) mode = "crop";
if (!Enum.TryParse(position, true, out AnchorPositionMode _)) position = "center";
if (!Color.TryParseHex("#" + background, out _)) background = "000000";
if (!int.TryParse(rotate, out _)) rotate = "0";
rotate = (int.Parse(rotate) < 0 || int.Parse(rotate) > 360) ? "0" : rotate;
if (!bool.TryParse(recreate, out _)) recreate = "false";
string imagepath = filepath.Replace(Path.GetExtension(filepath), "." + width.ToString() + "x" + height.ToString() + "." + mode.ToLower() + ".png"); string imagepath = filepath.Replace(Path.GetExtension(filepath), "." + width.ToString() + "x" + height.ToString() + ".png");
if (!System.IO.File.Exists(imagepath)) if (!System.IO.File.Exists(imagepath) || bool.Parse(recreate))
{ {
if ((_userPermissions.IsAuthorized(User, PermissionNames.Edit, file.Folder.Permissions) || if ((_userPermissions.IsAuthorized(User, PermissionNames.Edit, file.Folder.Permissions) ||
!string.IsNullOrEmpty(file.Folder.ImageSizes) && file.Folder.ImageSizes.ToLower().Split(",").Contains(width.ToString() + "x" + height.ToString())) !string.IsNullOrEmpty(file.Folder.ImageSizes) && file.Folder.ImageSizes.ToLower().Split(",").Contains(width.ToString() + "x" + height.ToString())))
&& Enum.TryParse(mode, true, out ResizeMode resizemode))
{ {
imagepath = CreateImage(filepath, width, height, resizemode.ToString(), rotate, imagepath); imagepath = CreateImage(filepath, width, height, mode, position, background, rotate, imagepath);
} }
else else
{ {
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Invalid Image Size For Folder Or Invalid Mode Specification {Folder} {Width} {Height} {Mode}", file.Folder, width, height, mode); _logger.Log(LogLevel.Error, this, LogFunction.Security, "Invalid Image Size For Folder {Folder} {Width} {Height}", file.Folder, width, height);
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
} }
} }
@ -569,35 +573,37 @@ namespace Oqtane.Controllers
return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null; return System.IO.File.Exists(errorPath) ? PhysicalFile(errorPath, MimeUtilities.GetMimeType(errorPath)) : null;
} }
private string CreateImage(string filepath, int width, int height, string mode, string rotate, string imagepath) private string CreateImage(string filepath, int width, int height, string mode, string position, string background, string rotate, string imagepath)
{ {
try try
{ {
FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read); using (var stream = new FileStream(filepath, FileMode.Open, FileAccess.Read))
using (Image image = Image.Load(stream))
{ {
stream.Position = 0;
using (var image = Image.Load(stream))
{
int.TryParse(rotate, out int angle);
Enum.TryParse(mode, true, out ResizeMode resizemode); Enum.TryParse(mode, true, out ResizeMode resizemode);
Enum.TryParse(position, true, out AnchorPositionMode anchorpositionmode);
image.Mutate(x => image.Mutate(x => x
x.Resize(new ResizeOptions .AutoOrient() // auto orient the image
.Rotate(angle)
.Resize(new ResizeOptions
{ {
Size = new Size(width, height), Mode = resizemode,
Mode = resizemode Position = anchorpositionmode,
Size = new Size(width, height)
}) })
.BackgroundColor(new Rgba32(255, 255, 255, 0))); .BackgroundColor(Color.ParseHex("#" + background)));
if (rotate != "0" && int.TryParse(rotate, out int angle))
{
image.Mutate(x => x.Rotate(angle));
}
image.Save(imagepath, new PngEncoder()); image.Save(imagepath, new PngEncoder());
} }
stream.Close(); }
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Error}", filepath, width, height, mode, ex.Message); _logger.Log(LogLevel.Error, this, LogFunction.Security, "Error Creating Image For File {FilePath} {Width} {Height} {Mode} {Rotate} {Error}", filepath, width, height, mode, rotate, ex.Message);
imagepath = ""; imagepath = "";
} }

View File

@ -158,6 +158,14 @@ namespace Oqtane.Infrastructure
nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay); nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay);
} }
break; break;
case "w": // weeks
nextExecution = nextExecution.AddDays(job.Interval * 7);
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)
{
// set the start time
nextExecution = nextExecution.Date.Add(job.StartDate.Value.TimeOfDay);
}
break;
case "M": // months case "M": // months
nextExecution = nextExecution.AddMonths(job.Interval); nextExecution = nextExecution.AddMonths(job.Interval);
if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0) if (job.StartDate != null && job.StartDate.Value.TimeOfDay.TotalSeconds != 0)

View File

@ -68,7 +68,7 @@ namespace Oqtane.SiteTemplates
new Permission(PermissionNames.View, RoleNames.Admin, true), new Permission(PermissionNames.View, RoleNames.Admin, true),
new Permission(PermissionNames.Edit, RoleNames.Admin, true) new Permission(PermissionNames.Edit, RoleNames.Admin, true)
}.EncodePermissions(), }.EncodePermissions(),
Content = "<p>Copyright (c) 2019-2021 .NET Foundation</p>" + Content = "<p>Copyright (c) 2018-2022 .NET Foundation</p>" +
"<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>" + "<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:</p>" +
"<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" + "<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>" +
"<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>" "<p>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</p>"

View File

@ -114,13 +114,16 @@ namespace Oqtane.Shared
public static string ImageUrl(Alias alias, int fileId, int width, int height, string mode) public static string ImageUrl(Alias alias, int fileId, int width, int height, string mode)
{ {
return ImageUrl(alias, fileId, width, height, mode, 0); return ImageUrl(alias, fileId, width, height, mode, "", "", 0, false);
} }
public static string ImageUrl(Alias alias, int fileId, int width, int height, string mode, int rotate) public static string ImageUrl(Alias alias, int fileId, int width, int height, string mode, string position, string background, int rotate, bool recreate)
{ {
var aliasUrl = (alias != null && !string.IsNullOrEmpty(alias.Path)) ? "/" + alias.Path : ""; var aliasUrl = (alias != null && !string.IsNullOrEmpty(alias.Path)) ? "/" + alias.Path : "";
return $"{aliasUrl}{Constants.ImageUrl}{fileId}/{width}/{height}/{mode}/{rotate}"; mode = string.IsNullOrEmpty(mode) ? "crop" : mode;
position = string.IsNullOrEmpty(position) ? "center" : position;
background = string.IsNullOrEmpty(background) ? "000000" : background;
return $"{aliasUrl}{Constants.ImageUrl}{fileId}/{width}/{height}/{mode}/{position}/{background}/{rotate}/{recreate}";
} }
public static string TenantUrl(Alias alias, string url) public static string TenantUrl(Alias alias, string url)