Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
return;
}

if (result.ElectionRoundStatus == ElectionRoundStatus.Archived
|| result.NgoStatus == NgoStatus.Deactivated
if (result.NgoStatus == NgoStatus.Deactivated
|| result.MonitoringNgoStatus == MonitoringNgoStatus.Suspended)
{
context.Fail();
Expand All @@ -46,4 +45,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

context.Succeed(requirement);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

if (ngoAdminResult is not null)
{
if (ngoAdminResult.ElectionRoundStatus == ElectionRoundStatus.Archived ||
ngoAdminResult.NgoStatus == NgoStatus.Deactivated ||
if (ngoAdminResult.NgoStatus == NgoStatus.Deactivated ||
ngoAdminResult.MonitoringNgoStatus == MonitoringNgoStatus.Suspended)
{
context.Fail();
Expand All @@ -66,4 +65,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

context.Fail();
}
}
}
3 changes: 0 additions & 3 deletions api/src/Feature.Coalitions/CoalitionsFeatureInstaller.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Dapper;
using Feature.NgoCoalitions.Models;
using Feature.NgoCoalitions.Services;
using Microsoft.Extensions.DependencyInjection;
using Vote.Monitor.Core.Converters;

Expand All @@ -12,8 +11,6 @@ public static IServiceCollection AddCoalitionsFeature(this IServiceCollection se
{
SqlMapper.AddTypeHandler(typeof(CoalitionMember[]), new JsonToObjectConverter<CoalitionMember[]>());

services.AddScoped<IFormSubmissionsCleanupService, FormSubmissionsCleanupService>();

return services;
}
}
20 changes: 2 additions & 18 deletions api/src/Feature.Coalitions/Delete/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using Feature.NgoCoalitions.Services;
namespace Feature.NgoCoalitions.Delete;

namespace Feature.NgoCoalitions.Delete;

public class Endpoint(VoteMonitorContext context, IFormSubmissionsCleanupService cleanupService)
public class Endpoint(VoteMonitorContext context)
: Endpoint<Request, Results<NoContent, NotFound, Conflict>>
{
public override void Configure()
Expand All @@ -25,20 +23,6 @@ public override async Task<Results<NoContent, NotFound, Conflict>> ExecuteAsync(
return TypedResults.NotFound();
}

// members data should be purged but coalition leader keeps their data
var membersToRemove = coalition
.Memberships
.Where(x => x.MonitoringNgoId != coalition.LeaderId)
.Select(x => x.MonitoringNgoId)
.ToList();

// Delete orphaned data
if (membersToRemove.Any())
{
await Task.WhenAll(membersToRemove.Select(monitoringNgoId =>
cleanupService.CleanupFormSubmissionsAsync(req.ElectionRoundId, req.CoalitionId, monitoringNgoId)));
}

context.Coalitions.Remove(coalition);
await context.SaveChangesAsync(ct);

Expand Down
18 changes: 0 additions & 18 deletions api/src/Feature.Coalitions/FormAccess/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using Authorization.Policies.Requirements;
using Feature.NgoCoalitions.Services;
using Microsoft.AspNetCore.Authorization;
using Vote.Monitor.Domain.Entities.CoalitionAggregate;

namespace Feature.NgoCoalitions.FormAccess;

public class Endpoint(
VoteMonitorContext context,
IFormSubmissionsCleanupService cleanupService,
IAuthorizationService authorizationService)
: Endpoint<Request, Results<NoContent, NotFound, ProblemDetails>>
{
Expand Down Expand Up @@ -69,26 +67,10 @@ public override async Task<Results<NoContent, NotFound, ProblemDetails>> Execute
.Select(x => x.Id)
.ToListAsync(ct);

var ngosWithRevokedAccess =
coalition.FormAccess
.Where(x => !coalitionMonitoringNgoIds.Contains(x.MonitoringNgoId))
.ToList();

var ngosGainedFormAccess =
coalitionMonitoringNgoIds.Where(x => coalition.FormAccess.All(fa => fa.MonitoringNgoId != x))
.Select(id => CoalitionFormAccess.Create(coalition.Id, id, req.FormId))
.ToList();

if (ngosWithRevokedAccess.Any())
{
context.CoalitionFormAccess.RemoveRange(ngosWithRevokedAccess);

foreach (var memberId in ngosWithRevokedAccess)
{
await cleanupService.CleanupFormSubmissionsAsync(
req.ElectionRoundId, req.CoalitionId, memberId.MonitoringNgoId, form.Id);
}
}

if (ngosGainedFormAccess.Any())
{
Expand Down

This file was deleted.

This file was deleted.

20 changes: 1 addition & 19 deletions api/src/Feature.Coalitions/Update/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
using Feature.NgoCoalitions.Models;
using Feature.NgoCoalitions.Services;
using Vote.Monitor.Domain.Entities.CoalitionAggregate;

namespace Feature.NgoCoalitions.Update;

public class Endpoint(VoteMonitorContext context, IFormSubmissionsCleanupService cleanupService)
public class Endpoint(VoteMonitorContext context)
: Endpoint<Request, Results<Ok<CoalitionModel>, NotFound, ProblemDetails>>
{
public override void Configure()
Expand Down Expand Up @@ -49,26 +48,9 @@ public override async Task<Results<Ok<CoalitionModel>, NotFound, ProblemDetails>
context.MonitoringNgos.Add(monitoringNgo);
}

var oldMembers = coalition.Memberships;

coalition.Update(req.CoalitionName,
coalitionMembers.Select(x => CoalitionMembership.Create(req.ElectionRoundId, req.CoalitionId, x.Id)));

var removedMembers = oldMembers
.Where(cm=>cm.MonitoringNgo.Id != coalition.LeaderId)
.Where(cm => coalitionMembers.All(x => x.Id != cm.MonitoringNgo.Id))
.Select(x => x.MonitoringNgo.Id)
.ToList();

// Delete orphaned data
if (removedMembers.Any())
{
foreach (var memberId in removedMembers)
{
await cleanupService.CleanupFormSubmissionsAsync(req.ElectionRoundId, req.CoalitionId, memberId);
}
}

await context.SaveChangesAsync(ct);
return TypedResults.Ok(CoalitionModel.FromEntity(coalition));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ public class MonitoringObserverModel
public string Email { get; init; }
public string PhoneNumber { get; init; }
public string[] Tags { get; init; }
public bool IsOwnObserver { get; init; }
public DateTime? LatestActivityAt { get; init; }
public MonitoringObserverStatus Status { get; init; }
}


3 changes: 1 addition & 2 deletions api/src/Feature.ObserverGuide/List/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ await authorizationService.AuthorizeAsync(User,

var isNgoAdmin = currentUserRoleProvider.IsNgoAdmin();
var isObserver = currentUserRoleProvider.IsObserver();



var observerId = currentUserProvider.GetUserId();
var ngoId = currentUserProvider.GetNgoId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public async Task HandleRequirementAsync_MonitoringNgoNotFound_Failure()
}

[Fact]
public async Task HandleRequirementAsync_ElectionRoundArchived_Failure()
public async Task HandleRequirementAsync_ElectionRoundArchived_Success()
{
// Arrange
_currentUserRoleProvider.IsNgoAdmin().Returns(true);
Expand All @@ -78,7 +78,7 @@ public async Task HandleRequirementAsync_ElectionRoundArchived_Failure()
await _handler.HandleAsync(_context);

// Assert
_context.HasSucceeded.Should().BeFalse();
_context.HasSucceeded.Should().BeTrue();
}

[Fact]
Expand Down
8 changes: 7 additions & 1 deletion web/src/components/dialogs/CreateDialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {
DialogTrigger,
} from '@/components/ui/dialog';
import { useTranslation } from "react-i18next";
import { useCurrentElectionRoundStore } from "@/context/election-round.store";
import { useElectionRoundDetails } from "@/features/election-event/hooks/election-event-hooks";
import { ElectionRoundStatus } from "@/common/types";

interface Props {
title?: ReactNode;
Expand All @@ -20,10 +23,13 @@ interface Props {
}

const CreateDialog = ({ title, description, children }: Props): ReactNode => {
const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId);

return (
<Dialog>
<DialogTrigger asChild>
<Button variant="default">
<Button variant="default" disabled={electionRound?.status === ElectionRoundStatus.Archived}>
<PlusIcon className="w-5 h-5 mr-2 -ml-1.5" />
<span>{title}</span>
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { useForm } from 'react-hook-form';
import { z } from 'zod';

import { authApi } from '@/common/auth-api';
import type { FunctionComponent } from '@/common/types';
import { ElectionRoundStatus, type FunctionComponent } from '@/common/types';
import { RichTextEditor } from '@/components/rich-text-editor';
import { toast } from '@/components/ui/use-toast';
import { useCurrentElectionRoundStore } from '@/context/election-round.store';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate, useRouter } from '@tanstack/react-router';
import { citizenNotificationsKeys } from '../hooks/citizen-notifications-queries';
import { Button } from '@/components/ui/button';
import { useElectionRoundDetails } from '@/features/election-event/hooks/election-event-hooks';

const createPushMessageSchema = z.object({
title: z.string().min(1, { message: 'Your message must have a title before sending.' }),
Expand All @@ -27,6 +28,8 @@ const createPushMessageSchema = z.object({
function CitizenNotificationMessageForm(): FunctionComponent {
const navigate = useNavigate();
const currentElectionRoundId = useCurrentElectionRoundStore((s) => s.currentElectionRoundId);
const { data: electionRound } = useElectionRoundDetails(currentElectionRoundId);

const router = useRouter();

const queryClient = useQueryClient();
Expand Down Expand Up @@ -113,7 +116,7 @@ function CitizenNotificationMessageForm(): FunctionComponent {
/>
</div>
<div className='flex flex-row-reverse w-full'>
<Button>Send notification</Button>
<Button disabled={electionRound?.status === ElectionRoundStatus.Archived}>Send notification</Button>
</div>
</form>
</Form>
Expand Down
Loading