174 lines
6.7 KiB
C#
174 lines
6.7 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Socialize.Api.Data;
|
|
|
|
namespace Socialize.Api.Modules.CalendarIntegrations.Services;
|
|
|
|
public class CalendarExportFeedService(AppDbContext dbContext, CalendarExportFeedBuilder feedBuilder)
|
|
{
|
|
public async Task<string> BuildUserFeedAsync(Guid userId, string? userEmail, string appBaseUrl, CancellationToken ct)
|
|
{
|
|
string normalizedEmail = userEmail?.Trim().ToUpperInvariant() ?? string.Empty;
|
|
Guid[] workspaceIds = await dbContext.Workspaces
|
|
.Where(workspace =>
|
|
workspace.OwnerUserId == userId ||
|
|
dbContext.OrganizationMemberships.Any(membership =>
|
|
membership.OrganizationId == workspace.OrganizationId &&
|
|
membership.UserId == userId))
|
|
.Select(workspace => workspace.Id)
|
|
.ToArrayAsync(ct);
|
|
|
|
List<CalendarExportFeedEvent> events = [];
|
|
|
|
events.AddRange(await dbContext.ContentItems
|
|
.Where(item => workspaceIds.Contains(item.WorkspaceId) && item.DueDate.HasValue)
|
|
.Join(
|
|
dbContext.Workspaces,
|
|
item => item.WorkspaceId,
|
|
workspace => workspace.Id,
|
|
(item, workspace) => new { item, workspace })
|
|
.Join(
|
|
dbContext.Clients,
|
|
itemWorkspace => itemWorkspace.item.ClientId,
|
|
client => client.Id,
|
|
(itemWorkspace, client) => new { itemWorkspace.item, itemWorkspace.workspace, client })
|
|
.Join(
|
|
dbContext.Campaigns,
|
|
itemWorkspaceClient => itemWorkspaceClient.item.CampaignId,
|
|
campaign => campaign.Id,
|
|
(itemWorkspaceClient, campaign) => new { itemWorkspaceClient.item, itemWorkspaceClient.workspace, itemWorkspaceClient.client, campaign })
|
|
.Select(candidate => ToContentFeedEvent(
|
|
candidate.item.Id,
|
|
candidate.item.Title,
|
|
candidate.item.Status,
|
|
candidate.item.DueDate!.Value,
|
|
candidate.workspace.Name,
|
|
candidate.client.Name,
|
|
candidate.campaign.Name,
|
|
appBaseUrl))
|
|
.ToListAsync(ct));
|
|
|
|
events.AddRange(await dbContext.ApprovalRequests
|
|
.Where(approval =>
|
|
approval.DueAt.HasValue &&
|
|
(approval.RequestedByUserId == userId ||
|
|
(!string.IsNullOrEmpty(normalizedEmail) && approval.ReviewerEmail.ToUpper() == normalizedEmail)))
|
|
.Join(
|
|
dbContext.ContentItems,
|
|
approval => approval.ContentItemId,
|
|
item => item.Id,
|
|
(approval, item) => new { approval, item })
|
|
.Where(candidate => workspaceIds.Contains(candidate.approval.WorkspaceId))
|
|
.Join(
|
|
dbContext.Workspaces,
|
|
approvalItem => approvalItem.approval.WorkspaceId,
|
|
workspace => workspace.Id,
|
|
(approvalItem, workspace) => new { approvalItem.approval, approvalItem.item, workspace })
|
|
.Select(candidate => ToApprovalFeedEvent(
|
|
candidate.approval.Id,
|
|
candidate.item.Id,
|
|
candidate.item.Title,
|
|
candidate.approval.Stage,
|
|
candidate.approval.State,
|
|
candidate.approval.DueAt!.Value,
|
|
candidate.workspace.Name,
|
|
appBaseUrl))
|
|
.ToListAsync(ct));
|
|
|
|
events.AddRange(await dbContext.Campaigns
|
|
.Where(campaign => workspaceIds.Contains(campaign.WorkspaceId))
|
|
.Join(
|
|
dbContext.Workspaces,
|
|
campaign => campaign.WorkspaceId,
|
|
workspace => workspace.Id,
|
|
(campaign, workspace) => new { campaign, workspace })
|
|
.Select(candidate => ToCampaignFeedEvent(
|
|
candidate.campaign.Id,
|
|
candidate.campaign.Name,
|
|
candidate.campaign.Status,
|
|
candidate.campaign.StartDate,
|
|
candidate.campaign.EndDate,
|
|
candidate.workspace.Name,
|
|
appBaseUrl))
|
|
.ToListAsync(ct));
|
|
|
|
return feedBuilder.Build("Socialize my work", events);
|
|
}
|
|
|
|
private static CalendarExportFeedEvent ToContentFeedEvent(
|
|
Guid contentItemId,
|
|
string title,
|
|
string status,
|
|
DateTimeOffset dueDate,
|
|
string workspaceName,
|
|
string clientName,
|
|
string campaignName,
|
|
string appBaseUrl)
|
|
{
|
|
(DateTimeOffset start, DateTimeOffset end, bool isAllDay) = NormalizeEventTime(dueDate);
|
|
|
|
return new CalendarExportFeedEvent(
|
|
$"content-{contentItemId}@socialize",
|
|
title,
|
|
start,
|
|
end,
|
|
isAllDay,
|
|
$"Status: {status}\nWorkspace: {workspaceName}\nClient: {clientName}\nCampaign: {campaignName}",
|
|
$"{appBaseUrl.TrimEnd('/')}/app/content/{contentItemId}");
|
|
}
|
|
|
|
private static CalendarExportFeedEvent ToApprovalFeedEvent(
|
|
Guid approvalId,
|
|
Guid contentItemId,
|
|
string contentTitle,
|
|
string stage,
|
|
string state,
|
|
DateTimeOffset dueAt,
|
|
string workspaceName,
|
|
string appBaseUrl)
|
|
{
|
|
(DateTimeOffset start, DateTimeOffset end, bool isAllDay) = NormalizeEventTime(dueAt);
|
|
|
|
return new CalendarExportFeedEvent(
|
|
$"approval-{approvalId}@socialize",
|
|
$"Approval due: {contentTitle}",
|
|
start,
|
|
end,
|
|
isAllDay,
|
|
$"Stage: {stage}\nState: {state}\nWorkspace: {workspaceName}",
|
|
$"{appBaseUrl.TrimEnd('/')}/app/content/{contentItemId}");
|
|
}
|
|
|
|
private static CalendarExportFeedEvent ToCampaignFeedEvent(
|
|
Guid campaignId,
|
|
string name,
|
|
string status,
|
|
DateTimeOffset startDate,
|
|
DateTimeOffset endDate,
|
|
string workspaceName,
|
|
string appBaseUrl)
|
|
{
|
|
DateTimeOffset start = new(startDate.Date, startDate.Offset);
|
|
DateTimeOffset end = new(endDate.Date.AddDays(1), endDate.Offset);
|
|
|
|
return new CalendarExportFeedEvent(
|
|
$"campaign-{campaignId}@socialize",
|
|
$"Campaign: {name}",
|
|
start,
|
|
end <= start ? start.AddDays(1) : end,
|
|
true,
|
|
$"Status: {status}\nWorkspace: {workspaceName}",
|
|
$"{appBaseUrl.TrimEnd('/')}/app/campaigns/{campaignId}");
|
|
}
|
|
|
|
private static (DateTimeOffset Start, DateTimeOffset End, bool IsAllDay) NormalizeEventTime(DateTimeOffset value)
|
|
{
|
|
if (value.TimeOfDay == TimeSpan.Zero)
|
|
{
|
|
DateTimeOffset start = new(value.Date, value.Offset);
|
|
return (start, start.AddDays(1), true);
|
|
}
|
|
|
|
return (value, value.AddMinutes(30), false);
|
|
}
|
|
}
|