Update API

This commit is contained in:
Chris Chen
2022-09-30 09:40:42 -07:00
parent 184db15773
commit b33c0d8286
55 changed files with 3877 additions and 360 deletions
Binary file not shown.
+3
View File
@@ -1,5 +1,6 @@
using Church.Net.Entity;
using Church.Net.Entity.Interface;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
@@ -7,6 +8,7 @@ using WebAPI.Logics.Interface;
namespace WebAPI.Controllers
{
[Authorize]
public class ApiControllerBase<T> : ControllerBase where T : IEntity
{
protected readonly ICrudLogic<T> logic;
@@ -74,6 +76,7 @@ namespace WebAPI.Controllers
}
}
[Authorize]
public class CombinedKeyApiControllerBase<T> : ControllerBase where T : ICombinedKeyEntity
{
protected readonly ICombinedKeyCrudLogic<T> logic;
+31 -23
View File
@@ -1,20 +1,18 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Church.Net.DAL.EF;
using Church.Net.Entity;
using Church.Net.Utility;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives;
using QRCoder;
using SixLabors.Fonts;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Processing;
using WebAPI.Logics.Interface;
// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
@@ -61,13 +59,15 @@ namespace WebAPI.Controllers
public async Task<IActionResult> GetInvitationQRcode(string id)
{
QRCodeGenerator gen = new QRCodeGenerator();
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode($"http://happiness.tours/invitation/{id}", QRCodeGenerator.ECCLevel.Q);
QRCodeData qrCodeData = qrGenerator.CreateQrCode($"https://happiness.tours/invitation/{id}", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
Bitmap qrCodeImage = qrCode.GetGraphic(3);
string qrCodeImagePath = ServerUtils.MapPath("App_Data/ScaneMeQrCode.png");
var backgroundBitmap = (Bitmap)Bitmap.FromFile(qrCodeImagePath);
var qrCodeImage = qrCode.GetGraphic(3);
string qrCodeImagePath = "/App_Data/ScaneMeQrCode.png";
var backgroundBitmap = SixLabors.ImageSharp.Image.Load(qrCodeImagePath);
//string qrCodeImagePath = Environment.GetEnvironmentVariable("AppData");
//HttpContext.Current.Server.MapPath("~/App_Data/");
//var fullPath = System.Web.Hosting.HostingEnvironment.MapPath(@"~/App_Data/ScaneMeQrCode.png");
@@ -81,9 +81,9 @@ namespace WebAPI.Controllers
using (var memoryStream = new MemoryStream())
{
//fileStream.CopyTo(memoryStream);
Bitmap image = Superimpose(best.Name, backgroundBitmap, qrCodeImage, 10, 32);
image.Scalling(75).Save(memoryStream, ImageFormat.Png);
var image = Superimpose(best.Name, backgroundBitmap, qrCodeImage, 10, 32);
image.Scalling(75);
image.SaveAsPng(memoryStream);
byte[] byteImage = memoryStream.ToArray();
return File(byteImage, "image/png");
}
@@ -91,12 +91,16 @@ namespace WebAPI.Controllers
return this.NotFound();
}
private Font arialFont;
[NonAction]
public Bitmap Superimpose(string bestName, Bitmap largeBmp, Bitmap smallBmp, int? x = null, int? y = null)
public Image Superimpose(string bestName, Image largeBmp, Image smallBmp, int? x = null, int? y = null)
{
Graphics g = Graphics.FromImage(largeBmp);
g.CompositingMode = CompositingMode.SourceOver;
smallBmp.MakeTransparent();
FontCollection collection = new();
FontFamily family = collection.Add("/App_Data/arial.ttf");
arialFont = family.CreateFont(12, FontStyle.Italic);
//Graphics g = Graphics.FromImage(largeBmp);
//g.CompositingMode = CompositingMode.SourceOver;
//smallBmp.MakeTransparent();
int margin = 5;
if (!x.HasValue)
{
@@ -109,9 +113,13 @@ namespace WebAPI.Controllers
var scale = 0.8;
var scaleWidth = (int)(smallBmp.Width * scale);
var scaleHeight = (int)(smallBmp.Height * scale);
g.DrawImage(smallBmp, new Rectangle(x.Value, y.Value, scaleWidth, scaleHeight));
g.DrawString(bestName, new Font(new FontFamily("Arial"), 12), new SolidBrush(System.Drawing.Color.Black), 10, 0);
largeBmp.Mutate(x => x.DrawText(bestName, arialFont, Color.Black, new PointF(10, 10)));
smallBmp.Scalling(80);
largeBmp.Mutate(ctx => ctx.DrawImage(smallBmp, new Point(x.Value, y.Value),1f));
return largeBmp;
}
+12 -9
View File
@@ -31,17 +31,15 @@ namespace WebAPI.Controllers
[Route("[controller]/[action]")]
public class LineMessageController : ControllerBase
{
private readonly ChurchNetContext dbContext;
private readonly LineAutoBotService lineAutoBotService;
private readonly ILoggingService loggingService;
public LineMessageController(ChurchNetContext dbContext,
public LineMessageController(
LineAutoBotService lineAutoBotService,
ILoggingService loggingService
)
{
this.dbContext = dbContext;
this.lineAutoBotService = lineAutoBotService;
this.loggingService = loggingService;
}
@@ -67,7 +65,9 @@ namespace WebAPI.Controllers
// POST api/<BestController>
[HttpPost]
public async Task PostFromLine([FromBody] object jsonData)
//[Route("[controller]/[action]")]
//[Route("[controller]/[action]/{id?}")]
public async Task PostFromLine(string id, [FromBody] object jsonData)
{
//string txtPath = ServerUtils.MapPath("App_Data/LinePostRawLog.txt");
@@ -76,7 +76,9 @@ namespace WebAPI.Controllers
{
LineWebhookContent content = JsonConvert.DeserializeObject<LineWebhookContent>(jsonData.ToString());
await lineAutoBotService.AutoReply(content);
//this.loggingService.Log("PostFromLine");
await lineAutoBotService.AutoReply(content);
}
catch (Exception ex)
{
@@ -103,14 +105,15 @@ namespace WebAPI.Controllers
}
[HttpGet]
public Task PushCommandMessage(string groupToken,string command)
public Task PushCommandMessage(string groupToken, string command)
{
return lineAutoBotService.PushCommandMessage(EnumHelper.GetEnumValueFromDescription<LineGroup>(groupToken), "#"+ command);
return lineAutoBotService.PushCommandMessage(EnumHelper.GetEnumValueFromDescription<LineGroup>(groupToken), "#" + command);
}
}
public class LineMessage{
public class LineMessage
{
public string To { get; set; }
public string Message { get; set; }
}
@@ -0,0 +1,35 @@
using Church.Net.Entity;
using LineMessaging;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;
using WebAPI.Logics;
using WebAPI.Logics.Interface;
namespace WebAPI.Controllers
{
[Route("[controller]/[action]")]
[ApiController]
public class LineMessagingAccountController : ApiControllerBase<LineMessagingAccount>
{
public LineMessagingAccountController(LineMessagingAccountLogic logic) : base(logic)
{
}
[HttpGet]
public void RefreshAllQuota()
{
foreach (var item in logic.GetAll())
{
if (!string.IsNullOrWhiteSpace(item.ChatToken))
{
var lineMessegeClient = new LineMessagingClient(item.ChatToken);
item.TotalUsage = lineMessegeClient.GetTotalUsage().Result;
logic.Update(item);
}
}
}
}
}
+37 -1
View File
@@ -1,10 +1,13 @@
using Church.Net.Entity;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using WebAPI.Logics.Interface;
using WebAPI.Services.Interfaces;
namespace WebAPI.Controllers
{
@@ -12,13 +15,46 @@ namespace WebAPI.Controllers
[ApiController]
public class LogController : ApiControllerBase<LogInfo>
{
public LogController(ICrudLogic<LogInfo> logic) : base(logic)
private readonly ILoggingService loggingService;
public LogController(
ICrudLogic<LogInfo> logic,
ILoggingService loggingService
) : base(logic)
{
this.loggingService = loggingService;
}
[HttpPost]
public void PurgeBefore([FromBody] DateTime date)
{
logic.Delete(l => l.Time <= date.ToUniversalTime());
}
[Route("/error-development")]
public IActionResult HandleErrorDevelopment(
[FromServices] IHostEnvironment hostEnvironment)
{
if (!hostEnvironment.IsDevelopment())
{
return NotFound();
}
var exceptionHandlerFeature =
HttpContext.Features.Get<IExceptionHandlerFeature>()!;
this.loggingService.Error(exceptionHandlerFeature.Error, exceptionHandlerFeature.Path);
return Problem(
detail: exceptionHandlerFeature.Error.StackTrace,
title: exceptionHandlerFeature.Error.Message);
}
[Route("/error")]
public IActionResult HandleError()
{
var exceptionHandlerFeature =
HttpContext.Features.Get<IExceptionHandlerFeature>()!;
this.loggingService.Error(exceptionHandlerFeature.Error, exceptionHandlerFeature.Path);
return Problem();
}
}
}
@@ -1,4 +1,5 @@
using Church.Net.DAL.EF;
using Church.Net.DAL.EFCoreDBF;
using Church.Net.Entity;
using Church.Net.Utility;
using Microsoft.AspNetCore.Mvc;
@@ -28,17 +29,16 @@ namespace WebAPI.Controllers
// POST api/<PasswordLoginController>
public PasswordLoginController(
ChurchNetContext churchNetContext,
ICrudLogic<FamilyMember> crudLogic,
ICombinedKeyCrudLogic<PastoralDomainMembers> relationLogic,
ICrudLogic<PastoralDomain> domainLogic
ICrudLogic<PastoralDomain> domainLogic,
DatabaseOptions databaseOptions
)
{
this.churchNetContext = churchNetContext;
this.crudLogic = crudLogic;
this.relationLogic = relationLogic;
this.domainLogic = domainLogic;
churchNetContext = databaseOptions.GetDbContext();
}
[HttpPost]
[Route("auth/login")]
+15 -7
View File
@@ -68,14 +68,14 @@ namespace WebAPI.Controllers
bool isGet = methodInfo.GetCustomAttributes(typeof(HttpGetAttribute), false).Length > 0;
bool isPost = methodInfo.GetCustomAttributes(typeof(HttpPostAttribute), false).Length > 0;
bool isDelete = methodInfo.GetCustomAttributes(typeof(HttpDeleteAttribute), false).Length > 0;
if(isGet|| isPost|| isDelete)
if (isGet || isPost || isDelete)
{
Endpoint _endpoint = new Endpoint
{
Name = methodInfo.Name,
Method = isGet ? "GET" : (isPost ? "POST" : (isDelete ? "DELETE" : "UNKNOWN")),
Inputs = methodInfo.GetParameters().Select(m=>new Input() { Name=m.Name}).ToArray(),
Inputs = methodInfo.GetParameters().Select(m => new Input() { Name = m.Name }).ToArray(),
ReturnType = methodInfo.ReturnType,
//MethodInfo = methodInfo,
};
@@ -92,7 +92,7 @@ namespace WebAPI.Controllers
}
return _controllers;
}
[HttpGet]
public async void TestMessage()
{
@@ -112,7 +112,7 @@ namespace WebAPI.Controllers
Uri = "https://happiness.tours/CellGroup/prayer?openExternalBrowser=1",
Label = "Prayer"
};
templateMessage.AltText= "代禱事項";
templateMessage.AltText = "代禱事項";
templateMessage.Template.DefaultAction = addPrayerBtn;
templateMessage.Template.ThumbnailImageUrl = "https://dailyverses.net/images/tc/cuv/matthew-21-22-3.jpg";
@@ -120,11 +120,11 @@ namespace WebAPI.Controllers
templateMessage.Template.Title = "代禱事項";
templateMessage.Template.Text = "Chris" + Environment.NewLine + "Testwerewiorjowerjiowejiro, erjaiworjweiorjioawereaw";
templateMessage.Template.Actions = new List<ILineAction>();
templateMessage.Template.Actions.Add(addPrayerBtn);
await test.PushMessage(EnumHelper.EnumToDescriptionString(LineGroup.Chris), textMessage);
await test.PushMessage(EnumHelper.EnumToDescriptionString(LineGroup.Chris), textMessage);
}
@@ -151,7 +151,7 @@ namespace WebAPI.Controllers
}
else
{
// ReplyTextMessage(replyToken, autoReply.ReplyMessage);
// ReplyTextMessage(replyToken, autoReply.ReplyMessage);
}
return;
@@ -162,6 +162,14 @@ namespace WebAPI.Controllers
};
}
[HttpGet]
public string[] GetFiles(string path)
{
return Directory.GetFiles("/App_Data/" + path);
}
public class Controller
{
public string Name { get; set; }
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
+1 -1
View File
@@ -9,7 +9,7 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebAPI/WebAPI.csproj", "WebAPI/"]
COPY ["Church.Net.DAL.EFCoreDBF/Church.Net.DAL.EFCoreDBF.csproj", "Church.Net.DAL.EFCoreDBF/"]
COPY ["Church.Net.Entity2/Church.Net.Entity2.csproj", "Church.Net.Entity2/"]
COPY ["Church.Net.Entity2/Church.Net.Entity.csproj", "Church.Net.Entity/"]
COPY ["Church.Net.Utility/Church.Net.Utility.csproj", "Church.Net.Utility/"]
RUN dotnet restore "WebAPI/WebAPI.csproj"
COPY . .
@@ -0,0 +1,43 @@
namespace WebAPI.Handlers
{
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Threading.Tasks;
public class BasicAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
private readonly AuthorizationMiddlewareResultHandler defaultHandler = new();
public async Task HandleAsync(
RequestDelegate next,
HttpContext context,
AuthorizationPolicy policy,
PolicyAuthorizationResult authorizeResult)
{
// If the authorization was forbidden and the resource had a specific requirement,
// provide a custom 404 response.
if (authorizeResult.Forbidden
&& authorizeResult.AuthorizationFailure!.FailedRequirements
.OfType<Show404Requirement>().Any())
{
// Return a 404 to make it appear as if the resource doesn't exist.
context.Response.StatusCode = StatusCodes.Status404NotFound;
return;
}
if (string.IsNullOrWhiteSpace(context.Request.Headers["accessToken"]))
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return;
}
// Fall back to the default implementation.
//await defaultHandler.HandleAsync(next, context, policy, authorizeResult);
await next(context);
}
}
public class Show404Requirement : IAuthorizationRequirement { }
}
+4
View File
@@ -7,21 +7,25 @@ using System;
using WebAPI.Logics.Core;
using WebAPI.Logics.Interface;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
namespace WebAPI.Logics
{
public class CellGroupLogic
{
private readonly IServiceScopeFactory serviceScopeFactory;
private readonly ICrudDAL<CellGroupRoutineEvent> eventCrudDAL;
private readonly ICombinedKeyCrudDAL<CellGroupRoutineEventAttendee> attendeeCrudDAL;
private readonly ICrudDAL<FamilyMember> memberCrudDAL;
public CellGroupLogic(
IServiceScopeFactory serviceScopeFactory,
ICrudDAL<CellGroupRoutineEvent> eventCrudDAL,
ICombinedKeyCrudDAL<CellGroupRoutineEventAttendee> attendeeCrudDAL,
ICrudDAL<FamilyMember> memberCrudDAL
)
{
this.serviceScopeFactory = serviceScopeFactory;
this.eventCrudDAL = eventCrudDAL;
this.attendeeCrudDAL = attendeeCrudDAL;
this.memberCrudDAL = memberCrudDAL;
+12 -12
View File
@@ -13,8 +13,8 @@ namespace WebAPI.Logics.Core
{
public class LogicBase<T> : ICrudLogic<T> where T : class, Church.Net.Entity.Interface.IEntity, new()
{
private readonly LogicService logicService;
private readonly ICrudDAL<T> crudDAL;
protected readonly LogicService logicService;
protected readonly ICrudDAL<T> crudDAL;
public LogicBase(
LogicService logicService,
@@ -46,15 +46,15 @@ namespace WebAPI.Logics.Core
public int CreateOrUpdate(T entity, out string id)
{
var result= this.crudDAL.CreateOrUpdate(entity, out string _id);
id = _id;
var result= this.crudDAL.CreateOrUpdate(entity);
id = entity.Id;
return result;
}
public string CreateReturnId(T entity)
{
return this.crudDAL.CreateReturnId(entity);
}
//public string CreateReturnId(T entity)
//{
// return this.crudDAL.CreateReturnId(entity);
//}
public int Delete(T obj)
{
@@ -75,10 +75,10 @@ namespace WebAPI.Logics.Core
return this.crudDAL.GetAll(filter);
}
public IEnumerable<T> GetAllById(IEnumerable<string> Ids)
{
return this.crudDAL.GetAllById(Ids);
}
//public IEnumerable<T> GetAllById(IEnumerable<string> Ids)
//{
// return this.crudDAL.GetAllById(Ids);
//}
public T GetById(string Id)
{
+20 -3
View File
@@ -1,16 +1,33 @@
using Church.Net.DAL.EF;
using Microsoft.Extensions.DependencyInjection;
using WebAPI.Services;
namespace WebAPI.Logics.Core
{
public class LogicService
{
private readonly IServiceScopeFactory serviceScopeFactory;
public LogicService(
ChurchNetContext dbContext
//ChurchNetContext dbContext
IServiceScopeFactory serviceScopeFactory
)
{
DbContext = dbContext;
this.serviceScopeFactory = serviceScopeFactory;
//DbContext = dbContext;
}
public ChurchNetContext DbContext { get; }
//public ChurchNetContext DbContext { get; }
public string CurrentUserId
{
get
{
using (var scope = serviceScopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetService<IdentityService>();
return service.UserId;
}
}
}
}
}
+2 -2
View File
@@ -37,7 +37,7 @@ namespace WebAPI.Logics
{
var week = GetHappinessWeek(group, i);
group.Weeks.Add(week);
weekCrudDAL.CreateOrUpdate(week, out string weekId);
weekCrudDAL.CreateOrUpdate(week);
}
}
group.Weeks = group.Weeks.OrderBy(w => w.SEQ).ToList();
@@ -66,7 +66,7 @@ namespace WebAPI.Logics
}
return weekCrudDAL.UpdateRange(list);
}
return weekCrudDAL.CreateOrUpdate(value, out string id);
return weekCrudDAL.CreateOrUpdate(value);
}
+2 -2
View File
@@ -13,10 +13,10 @@ namespace WebAPI.Logics.Interface
T GetById(string Id);
IEnumerable<T> GetAll(Func<T, bool> filter = null);
IEnumerable<T> GetAllById(IEnumerable<string> Ids);
//IEnumerable<T> GetAllById(IEnumerable<string> Ids);
int Create(T entity);
Task<int> CreateAsync(T entity);
string CreateReturnId(T entity);
//string CreateReturnId(T entity);
int CreateOrUpdate(T entity, out string id);
int Update(T entity);
@@ -0,0 +1,49 @@
using Church.Net.DAL.EFCoreDBF;
using Church.Net.Entity;
using Church.Net.Entity.Interface;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using WebAPI.Logics.Core;
using WebAPI.Logics.Interface;
namespace WebAPI.Logics
{
public class LineMessagingAccountLogic : LogicBase<LineMessagingAccount>, ICrudLogic<LineMessagingAccount>
{
private readonly ICrudDAL<HappinessGroup> happinessGroupDAL;
private readonly ICrudDAL<PastoralDomain> cellGroupDAL;
public LineMessagingAccountLogic(
LogicService logicService,
ICrudDAL<LineMessagingAccount> crudDAL,
ICrudDAL<HappinessGroup> happinessGroupDAL,
ICrudDAL<PastoralDomain> cellGroupDAL
) : base(logicService, crudDAL)
{
this.happinessGroupDAL = happinessGroupDAL;
this.cellGroupDAL = cellGroupDAL;
}
public HappinessGroup GetHappinessGroup(string lineGroupId)
{
var group= happinessGroupDAL.First(c => c.CommunityAppId == lineGroupId);
GetLineMessagingAccount(group);
return group;
}
public PastoralDomain GetCellGroup(string lineGroupId)
{
var group = cellGroupDAL.First(c => c.CommunityAppId == lineGroupId);
GetLineMessagingAccount(group);
return group;
}
private void GetLineMessagingAccount(IMessengerClient messengerClient)
{
if (messengerClient != null)
{
messengerClient.LineMessagingAccount = crudDAL.GetById(messengerClient.LineAccountId);
}
}
}
}
@@ -16,10 +16,9 @@ namespace WebAPI.Services.AutoReplyCommands
public class ArArkCellGroupDinner : IAutoReplyCommand
{
public ArArkCellGroupDinner(ChurchNetContext context,
public ArArkCellGroupDinner(
CellGroupLogic logic)
{
this._context = context;
this.logic = logic;
}
private static readonly string[] COMMANDS = { "晚餐", "dinner" };
@@ -28,57 +27,12 @@ namespace WebAPI.Services.AutoReplyCommands
LineGroup.Ark,
LineGroup.Chris,
};
private readonly ChurchNetContext _context;
private readonly CellGroupLogic logic;
public string Description => "顯示方舟小組聚會晚餐";
public IEnumerable<string> Commands => COMMANDS;
public IEnumerable<LineGroup> SupportGroups => GROUPS;
public IEnumerable<string> ReplyMessage
{
get
{
StringBuilder sb = new StringBuilder();
StringBuilder comments = new StringBuilder();
sb.AppendLine("又到了令人期待的小組日~~~");
var _event = _context.CellGroupRoutineEvents.Where(e => e.Time >= DateTime.Today)
.Include(e => e.Attendees).FirstOrDefault();
if (_event == null)
{
_event = new CellGroupRoutineEvent()
{
Id = Format.Get33BaseGuid(),
Time = DateTimeHelper.GetNextWeekday(DateTime.Today, DayOfWeek.Friday).AddHours(19).AddMinutes(30),
Address = "1881 Forest Dr., Azusa, CA 91702",
Attendees = new List<CellGroupRoutineEventAttendee>()
};
_context.Add(_event);
_context.SaveChanges();
}
sb.AppendLine($"{_event.Time.ToString("MM/dd HH:mm tt")} 開飯~");
sb.AppendLine("======= 晚宴清單 =======");
foreach (var a in _event.Attendees)
{
sb.AppendLine($"{a.Name} - {string.Join(", ", a.PotluckItem.Split('|'))}");
if (!string.IsNullOrWhiteSpace(a.Comment))
{
comments.AppendLine($"{a.Name}:{a.Comment}");
}
}
if (comments.Length > 0)
{
sb.AppendLine("========= 備註 =========");
sb.Append(comments.ToString());
}
return new string[] { sb.ToString() };
}
}
public IEnumerable<string> ReplyMessage => null;
public IEnumerable<ILineMessage> LineMessage
{
@@ -231,7 +231,8 @@ namespace WebAPI.Services.AutoReplyCommands
{
Size = FlexObjectSize.sm,
Color = "#666666",
Flex = 5
Flex = 5,
Wrap = true
});
comments.Add(commentLineBox);
}
+2 -2
View File
@@ -127,12 +127,12 @@ namespace WebAPI.Services
EventLog.WriteEntry("BeyondAPI", $"Can Not Append Error Log:{ex.Message}", EventLogEntryType.Error);
}
public void Log(string message, object detail)
public void Log(string message, object detail = null)
{
LogInfo log = new LogInfo(LogLevel.Info)
{
Message = message,
DetailMessage = JsonConvert.SerializeObject(detail,Formatting.Indented) ,
DetailMessage = JsonConvert.SerializeObject(detail, Formatting.Indented),
//Source = exception.Source,
//StackTrace = exception.StackTrace
};
+26
View File
@@ -0,0 +1,26 @@
using Church.Net.Entity;
using Church.Net.Utility;
using Microsoft.AspNetCore.SignalR;
namespace WebAPI.Services
{
public class IdentityService
{
public string UserAccessToken { get; set; }
public string UserId { get; set; }
public PastoralDomain CellGroup
{
get {
TokenHelper.GetUserIdFromToken
return null; }
}
}
}
@@ -7,7 +7,7 @@ namespace WebAPI.Services.Interfaces
{
public interface ILoggingService
{
void Log(string message, object detail);
void Log(string message, object detail=null);
void Warning(string message, object detail);
int Error(Exception exception);
int Error(Exception exception, string from);
@@ -0,0 +1,15 @@
using LineMessaging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace WebAPI.Services.Interfaces
{
public interface IScheduledTask
{
string Description { get; }
bool CheckTime(DateTime time);
Task<bool> RunTask();
}
}
+54 -65
View File
@@ -1,4 +1,5 @@
using Church.Net.Utility;
using Church.Net.Entity.Messenger;
using Church.Net.Utility;
using LineMessaging;
using Microsoft.Extensions.Logging.Abstractions;
using Newtonsoft.Json;
@@ -8,6 +9,7 @@ using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebAPI.Logics.Interface;
using WebAPI.Services.Interfaces;
using static System.Net.Mime.MediaTypeNames;
@@ -27,14 +29,17 @@ namespace WebAPI.Services
{
private readonly IEnumerable<IAutoReplyCommand> autoReplyCommands;
private readonly ILoggingService loggingService;
private readonly ICrudLogic<LineMessageClient> clientLogic;
public LineAutoBotService(
IEnumerable<IAutoReplyCommand> autoReplyCommands,
ILoggingService loggingService
ILoggingService loggingService,
ICrudLogic<LineMessageClient> clientLogic
)
{
this.autoReplyCommands = autoReplyCommands;
this.loggingService = loggingService;
this.clientLogic = clientLogic;
}
public void SendTextMessage(string text, LineGroup target)
{
@@ -72,7 +77,12 @@ namespace WebAPI.Services
}
catch (Exception ex)
{
this.loggingService.Error(ex, "ReplyTextMessage:68", JsonConvert.SerializeObject(replyMessage, Formatting.Indented));
this.loggingService.Error(ex, "ReplyTextMessage:75", JsonConvert.SerializeObject(replyMessage, Formatting.Indented));
if (ex.Message == "You have reached your monthly limit.")
{
this.SendTextMessage("Line Bot Exist Monthly Limit!!!", LineGroup.Chris);
}
return false;
}
}
@@ -92,7 +102,11 @@ namespace WebAPI.Services
}
catch (Exception ex)
{
this.loggingService.Error(ex, "ReplyLineMessage:84", JsonConvert.SerializeObject(replyMessage, Formatting.Indented));
this.loggingService.Error(ex, "ReplyLineMessage:95", JsonConvert.SerializeObject(replyMessage, Formatting.Indented));
if (ex.Message == "You have reached your monthly limit.")
{
this.SendTextMessage("Line Bot Exist Monthly Limit!!!", LineGroup.Chris);
}
return false;
}
@@ -112,10 +126,13 @@ namespace WebAPI.Services
string replyToken = e.ReplyToken;
string text = e.Message.Text;
string target = "";
bool isGroup = true;
var client = new LineMessagingClient();
switch (e.Source.Type)
{
case WebhookRequestSourceType.User:
target = e.Source.UserId;
isGroup = false;
break;
case WebhookRequestSourceType.Group:
target = e.Source.GroupId;
@@ -127,6 +144,33 @@ namespace WebAPI.Services
default:
break;
}
if (isGroup)
{
if (clientLogic.First(c => c.ClientId == e.Source.GroupId) == null)
{
clientLogic.CreateOrUpdate(new LineMessageClient()
{
ClientId = target,
Name = client.GetGroupProfile(e.Source.GroupId).Result.GroupName,
IsGroup = true
}, out string id);
}
//TODO:Get user by user id under group
}
else
{
if (clientLogic.First(c => c.ClientId == e.Source.UserId) == null)
{
clientLogic.CreateOrUpdate(new LineMessageClient()
{
ClientId = target,
Name = client.GetProfile(e.Source.UserId).Result.DisplayName,
IsGroup = false
}, out string id);
}
}
if (!String.IsNullOrWhiteSpace(replyToken) && text.IndexOf("#") == 0)
{
@@ -166,8 +210,12 @@ namespace WebAPI.Services
}
else if (e.Message.Type == MessageType.Sticker && e.Source.GroupId == LineGroup.Ark.EnumToDescriptionString() && e.Message.PackageId == "1011092" && e.Message.StickerId == "510712")
{
await ReplyLineMessage(e.Source.GroupId, autoReplyCommands.Where(ar => ar.Commands.Contains("pray")).FirstOrDefault().LineMessage);
}
this.LogLineMessage(e);
}
}
catch (Exception ex)
@@ -224,7 +272,7 @@ namespace WebAPI.Services
}
catch (Exception ex)
{
loggingService.Error(ex, "AutoReply:188",command);
loggingService.Error(ex, "AutoReply:188", command);
return false;
}
@@ -232,64 +280,5 @@ namespace WebAPI.Services
return true;
}
private void LogLineMessage(LineWebhookContent.Event e)
{
return;
try
{
//var lineHookRequest = new LineMessaging.LineWebhookRequest("d23edf453427256a759d218ec8b6779f", request);
//var content = await lineHookRequest.GetContent();
string txtPath = ServerUtils.MapPath("App_Data/LinePostLog.txt");
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"==================={DateTime.Now.ToString("MM/dd/yyyy HH:mm")}=========================");
stringBuilder.AppendLine($"Message Type:{e.Type.ToString()}");
switch (e.Source.Type)
{
case WebhookRequestSourceType.User:
stringBuilder.AppendLine($"UserId:{e.Source.UserId}");
break;
case WebhookRequestSourceType.Group:
stringBuilder.AppendLine($"GroupId:{e.Source.GroupId}");
break;
case WebhookRequestSourceType.Room:
stringBuilder.AppendLine($"RoomId:{e.Source.RoomId}");
break;
default:
break;
}
stringBuilder.AppendLine($"Reply Token:{e.ReplyToken}");
stringBuilder.AppendLine($"Message Type:{e.Message.Type.ToString()}");
switch (e.Message.Type)
{
case MessageType.Text:
stringBuilder.AppendLine($"Message:{e.Message.Text}");
break;
case MessageType.Image:
case MessageType.Video:
case MessageType.Audio:
case MessageType.File:
case MessageType.Location:
case MessageType.Sticker:
case MessageType.Imagemap:
case MessageType.Template:
default:
stringBuilder.AppendLine($"Message:{JsonConvert.SerializeObject(e.Message, Formatting.Indented)}");
break;
}
System.IO.File.AppendAllText(txtPath, stringBuilder.ToString());
}
catch (Exception ex)
{
}
}
}
}
@@ -0,0 +1,46 @@
using Church.Net.Utility;
using System;
using System.Threading.Tasks;
using WebAPI.Services.Interfaces;
namespace WebAPI.Services.ScheduledTask
{
public class MorningPrayer : IScheduledTask
{
private readonly LineAutoBotService lineAutoBotService;
private readonly ILoggingService loggingService;
private DateTime? nextRunningTime = null;
public MorningPrayer(
LineAutoBotService lineAutoBotService,
ILoggingService loggingService
)
{
this.lineAutoBotService = lineAutoBotService;
this.loggingService = loggingService;
this.SetNextRunningTime();
}
public string Description => "Sent out Ark Morning Prayer";
public bool CheckTime(DateTime time)
{
if(nextRunningTime == null)
{
this.SetNextRunningTime();
return true;
}
return time >= nextRunningTime.Value;
}
public Task<bool> RunTask()
{
SetNextRunningTime();
return lineAutoBotService.PushCommandMessage(LineGroup.Ark, "#pray");
}
private void SetNextRunningTime()
{
nextRunningTime = DateTimeHelper.Today().AddDays(1).AddHours(8);
loggingService.Log($"Scheduled Task {this.Description}", nextRunningTime.Value);
}
}
}
+70
View File
@@ -0,0 +1,70 @@
using Microsoft.Extensions.Hosting;
using System.Threading.Tasks;
using System.Threading;
using System;
using WebAPI.Services.Interfaces;
using System.Collections.Generic;
using System.Linq;
using Church.Net.Utility;
using Microsoft.AspNetCore.Hosting;
namespace WebAPI.Services
{
public class WorkerService : BackgroundService
{
private IEnumerable<IScheduledTask> scheduledTasks;
private ILoggingService loggingService;
private readonly IWebHostEnvironment env;
private static bool initialized = false;
public WorkerService(
IEnumerable<IScheduledTask> scheduledTasks,
ILoggingService loggingService
)
{
this.scheduledTasks = scheduledTasks;
this.loggingService = loggingService;
}
private const int generalDelay = 5 * 60 * 1000; // 10 seconds
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
//await DoBackupAsync();
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(generalDelay, stoppingToken);
await DoBackupAsync();
}
}
private async Task<string> DoBackupAsync()
{
// here i can write logic for taking backup at midnight
//if (IsMidnight())
//{
// Console.WriteLine("Executing background task");
// TakeBackup();
//}
var now = DateTimeHelper.Now();
foreach (var worker in scheduledTasks)
{
try
{
if (worker.CheckTime(now))
{
loggingService.Log($"Running {worker.Description}");
await worker.RunTask();
}
}
catch (Exception ex)
{
loggingService.Error(ex, worker.Description);
}
}
return "Done";
}
}
}
+42 -59
View File
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Church.Net.DAL.EF;
using Church.Net.DAL.EFCoreDBF;
using Church.Net.Entity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Hosting;
@@ -18,6 +19,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Serialization;
using WebAPI.Handlers;
using WebAPI.Hubs;
using WebAPI.Logics;
using WebAPI.Logics.Core;
@@ -25,6 +27,7 @@ using WebAPI.Logics.Interface;
using WebAPI.Services;
using WebAPI.Services.AutoReplyCommands;
using WebAPI.Services.Interfaces;
using WebAPI.Services.ScheduledTask;
using static System.Net.Mime.MediaTypeNames;
namespace WebAPI
@@ -51,7 +54,7 @@ namespace WebAPI
NamingStrategy = new CamelCaseNamingStrategy(),
};
options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Unspecified;
//options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Unspecified;
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
@@ -60,6 +63,7 @@ namespace WebAPI
services.AddSignalR();
services.AddSingleton<GameRoomLogic>();
services.AddSingleton(_ => new DatabaseOptions { ConnectionString = "Host=192.168.86.131;Port=49154;Database=Church;Username=chris;Password=1124" });
//services.AddSingleton<ChurchNetContext>(new ChurchNetContext());
services.AddDbContext<ChurchNetContext>(options =>
options.UseNpgsql(
@@ -67,30 +71,37 @@ namespace WebAPI
"Host=192.168.86.131;Port=49154;Database=Church;Username=chris;Password=1124"
));
services.AddTransient<LineAutoBotService>();
services.AddTransient<IAutoReplyCommand, ArChurchInfo>();
services.AddTransient<IAutoReplyCommand, ArArkCellGroupInfo>();
services.AddTransient<IAutoReplyCommand, ArArkCellGroupDinner>();
services.AddTransient<IAutoReplyCommand, ArArkCellGroupPrayer>();
services.AddSingleton<LineAutoBotService>();
services.AddSingleton<IAutoReplyCommand, ArChurchInfo>();
services.AddSingleton<IAutoReplyCommand, ArArkCellGroupInfo>();
services.AddSingleton<IAutoReplyCommand, ArArkCellGroupDinner>();
services.AddSingleton<IAutoReplyCommand, ArArkCellGroupPrayer>();
services.AddSingleton<IScheduledTask, MorningPrayer>();
services.AddSingleton<VideoDownloadLogic>();
services.AddScoped<LogicService>();
services.AddScoped<CellGroupLogic>();
services.AddScoped(typeof(ICrudLogic<>), typeof(LogicBase<>));
services.AddScoped(typeof(ICrudDAL<>), typeof(CrudDALCBase<>));
services.AddScoped(typeof(ICombinedKeyCrudLogic<>), typeof(CombinedKeyLogicBase<>));
services.AddScoped(typeof(ICombinedKeyCrudDAL<>), typeof(CombinedKeyCrudDALCBase<>));
services.AddScoped<HappinessGroupLogic>();
services.AddTransient<ILoggingService, DbLoggingService>();
services.AddSingleton<LogicService>();
services.AddSingleton<CellGroupLogic>();
services.AddSingleton(typeof(ICrudLogic<>), typeof(LogicBase<>));
services.AddSingleton(typeof(ICrudDAL<>), typeof(CrudDALCBase<>));
services.AddSingleton(typeof(ICombinedKeyCrudLogic<>), typeof(CombinedKeyLogicBase<>));
services.AddSingleton(typeof(ICombinedKeyCrudDAL<>), typeof(CombinedKeyCrudDALCBase<>));
services.AddSingleton<HappinessGroupLogic>();
services.AddSingleton<LineMessagingAccountLogic>();
services.AddSingleton<ILoggingService, DbLoggingService>();
services.AddScoped<IdentityService>();
services.AddHostedService<WorkerService>();
//services.AddMvc(o=>o.Filters.Add(typeof(HandleExceptionFilter)));
//services.AddMvc(o => o.Filters.Add(new HandleExceptionFilter(services.BuildServiceProvider().GetService<ILoggingService>())));
//services.BuildServiceProvider().GetService<ILoggingService>();
services.AddSingleton<IAuthorizationMiddlewareResultHandler, BasicAuthorizationMiddlewareResultHandler>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ChurchNetContext dbContext)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DatabaseOptions databaseOptions)
{
//Reference:https://stackoverflow.com/questions/69961449/net6-and-datetime-problem-cannot-write-datetime-with-kind-utc-to-postgresql-ty
@@ -101,7 +112,12 @@ namespace WebAPI
AppDomain.CurrentDomain.SetData("WebRootPath", env.WebRootPath);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseDeveloperExceptionPage();
app.UseExceptionHandler("/error-development");
}
else
{
app.UseExceptionHandler("/error");
}
// global cors policy
@@ -113,18 +129,16 @@ namespace WebAPI
.AllowCredentials()
); // allow credentials
//app.UseCors(builder =>
//{
// builder.WithOrigins("http://localhost:4200")
// .AllowAnyHeader()
// .WithMethods("GET", "POST")
// .AllowCredentials();
//});
//app.UseHttpsRedirection();
//app.UsePathBase(new PathString("/api"));
app.UsePathBase(new PathString("/"));
app.UseRouting();
//app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
//endpoints.MapControllerRoute(
@@ -135,50 +149,19 @@ namespace WebAPI
endpoints.MapHub<BaseHub>("/BaseHub");
endpoints.MapControllers();
//endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller}/{action=Index}/{id?}");
});
//app.UseExceptionHandler(exceptionHandlerApp =>
//{
// exceptionHandlerApp.Run(async context =>
// {
// context.Response.StatusCode = StatusCodes.Status500InternalServerError;
// // using static System.Net.Mime.MediaTypeNames;
// context.Response.ContentType = Text.Plain;
// await context.Response.WriteAsync("An exception was thrown.");
// var exceptionHandlerPathFeature =
// context.Features.Get<IExceptionHandlerPathFeature>();
// if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
// {
// await context.Response.WriteAsync(" The file was not found.");
// }
// if (exceptionHandlerPathFeature?.Path == "/")
// {
// await context.Response.WriteAsync(" Page: Home.");
// }
// });
//});
//app.UseAuthorization();
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllers();
// endpoints.MapHub<WhoIsSpyHub>("/WhoIsSpyHub");
//});
if (env.IsDevelopment())
{
databaseOptions.GetDbContext().Database.Migrate();
//new ChurchNetContext(databaseOptions.ConnectionString).Database.Migrate();
//dbContext.Database.EnsureCreated();
dbContext.Database.Migrate();
//dbContext.Database.Migrate();
}
}
}
}
+4 -1
View File
@@ -17,6 +17,7 @@
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Controllers\PasswordLogin\" />
<Folder Include="Filters\" />
</ItemGroup>
<ItemGroup>
@@ -38,8 +39,10 @@
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.9" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.8" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="QRCoder" Version="1.4.1" />
<PackageReference Include="QRCoder-ImageSharp" Version="0.9.0" />
<PackageReference Include="SharpGrabber.YouTube" Version="1.4.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta15" />
</ItemGroup>
<ItemGroup>