mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-07-15 16:27:26 +02:00
Fix pagination has next page on campaign page. Fix campaign recipients return standard T[] result. Fix anonymization affected recipient outside scope.
Signed-off-by: Ronni Skansing <rskansing@gmail.com>
This commit is contained in:
@@ -735,7 +735,6 @@ func (c *Campaign) GetRecipientsByCampaignID(g *gin.Context) {
|
||||
}
|
||||
// endpoints is handled a bit differently and allows to
|
||||
// fetch an unlimited amount of rows if no offset and limit is set.
|
||||
// TODO this endpoint should be changed to a Result<T> so we fetch the rows as needed.
|
||||
offset := g.DefaultQuery("offset", "")
|
||||
limit := g.DefaultQuery("limit", "")
|
||||
// parse request
|
||||
|
||||
@@ -159,11 +159,11 @@ func (r *CampaignRecipient) GetByCampaignID(
|
||||
ctx context.Context,
|
||||
campaignID *uuid.UUID,
|
||||
options *CampaignRecipientOption,
|
||||
) ([]*model.CampaignRecipient, error) {
|
||||
recps := []*model.CampaignRecipient{}
|
||||
) (*model.Result[model.CampaignRecipient], error) {
|
||||
result := model.NewEmptyResult[model.CampaignRecipient]()
|
||||
db, err := useQuery(r.DB, database.CAMPAIGN_TABLE, options.QueryArgs, allowedCampaignRecipientColumns...)
|
||||
if err != nil {
|
||||
return recps, errs.Wrap(err)
|
||||
return result, errs.Wrap(err)
|
||||
}
|
||||
db = r.preload(db, options)
|
||||
var dbCampaignRecipients []database.CampaignRecipient
|
||||
@@ -176,16 +176,23 @@ func (r *CampaignRecipient) GetByCampaignID(
|
||||
Find(&dbCampaignRecipients)
|
||||
|
||||
if res.Error != nil {
|
||||
return recps, res.Error
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
hasNextPage, err := useHasNextPage(db, database.CAMPAIGN_RECIPIENT_TABLE_NAME, options.QueryArgs, allowedCampaignRecipientColumns...)
|
||||
if err != nil {
|
||||
return result, errs.Wrap(err)
|
||||
}
|
||||
result.HasNextPage = hasNextPage
|
||||
|
||||
for _, dbCampaignRecipient := range dbCampaignRecipients {
|
||||
r, err := ToCampaignRecipient(&dbCampaignRecipient)
|
||||
if err != nil {
|
||||
return recps, nil
|
||||
return result, nil
|
||||
}
|
||||
recps = append(recps, r)
|
||||
result.Rows = append(result.Rows, r)
|
||||
}
|
||||
return recps, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetByID gets a campaign recipient by id
|
||||
@@ -414,6 +421,7 @@ func (c *CampaignRecipient) UpdateByID(
|
||||
// Anonymize adds an anonymized id to a campaign recipient
|
||||
func (r *CampaignRecipient) Anonymize(
|
||||
ctx context.Context,
|
||||
campaignID *uuid.UUID,
|
||||
recipientID *uuid.UUID,
|
||||
anonymizedID *uuid.UUID,
|
||||
) error {
|
||||
@@ -421,10 +429,17 @@ func (r *CampaignRecipient) Anonymize(
|
||||
"anonymized_id": anonymizedID.String(),
|
||||
}
|
||||
AddUpdatedAt(row)
|
||||
res := r.DB.
|
||||
Model(&database.CampaignRecipient{}).
|
||||
Where("recipient_id = ?", recipientID).
|
||||
Updates(row)
|
||||
db := r.DB.Model(&database.CampaignRecipient{})
|
||||
|
||||
// if campaignID is nil, anonymize across all campaigns (e.g., when deleting recipient)
|
||||
// otherwise, only anonymize for the specific campaign
|
||||
if campaignID != nil {
|
||||
db = db.Where("campaign_id = ? AND recipient_id = ?", campaignID, recipientID)
|
||||
} else {
|
||||
db = db.Where("recipient_id = ?", recipientID)
|
||||
}
|
||||
|
||||
res := db.Updates(row)
|
||||
|
||||
if res.Error != nil {
|
||||
return res.Error
|
||||
|
||||
+14
-14
@@ -871,15 +871,15 @@ func (c *Campaign) GetRecipientsByCampaignID(
|
||||
session *model.Session,
|
||||
campaignID *uuid.UUID,
|
||||
options *repository.CampaignRecipientOption,
|
||||
) ([]*model.CampaignRecipient, error) {
|
||||
) (*model.Result[model.CampaignRecipient], error) {
|
||||
ae := NewAuditEvent("Campaign.GetRecipientsByCampaignID", session)
|
||||
ae.Details["campaignId"] = campaignID.String()
|
||||
recipients := []*model.CampaignRecipient{}
|
||||
result := model.NewEmptyResult[model.CampaignRecipient]()
|
||||
// check permissions
|
||||
isAuthorized, err := IsAuthorized(session, data.PERMISSION_ALLOW_GLOBAL)
|
||||
if err != nil && !errors.Is(err, errs.ErrAuthorizationFailed) {
|
||||
c.LogAuthError(err)
|
||||
return recipients, errs.Wrap(err)
|
||||
return result, errs.Wrap(err)
|
||||
}
|
||||
if !isAuthorized {
|
||||
c.AuditLogNotAuthorized(ae)
|
||||
@@ -889,17 +889,17 @@ func (c *Campaign) GetRecipientsByCampaignID(
|
||||
if options.OrderBy == "" {
|
||||
options.OrderBy = "campaign_recipients.sent_at"
|
||||
}
|
||||
recipients, err = c.CampaignRecipientRepository.GetByCampaignID(
|
||||
result, err = c.CampaignRecipientRepository.GetByCampaignID(
|
||||
ctx,
|
||||
campaignID,
|
||||
options,
|
||||
)
|
||||
if err != nil {
|
||||
c.Logger.Errorw("failed to get recipients by campaign id", "error", err)
|
||||
return recipients, errs.Wrap(err)
|
||||
return result, errs.Wrap(err)
|
||||
}
|
||||
// no audit on read
|
||||
return recipients, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetEventsByCampaignID gets all events for a campaign
|
||||
@@ -3206,7 +3206,7 @@ func (c *Campaign) AnonymizeByID(
|
||||
// assign a anonymized ID to each campaign recipient and make a map between
|
||||
// their ID and the anonymized ID, this is a itermidiate step to anonymize the events
|
||||
// where campaign receipients have both a anonymized ID and the recipient ID
|
||||
campaignRecipients, err := c.CampaignRecipientRepository.GetByCampaignID(
|
||||
campaignRecipientsResult, err := c.CampaignRecipientRepository.GetByCampaignID(
|
||||
ctx,
|
||||
id,
|
||||
&repository.CampaignRecipientOption{},
|
||||
@@ -3215,7 +3215,7 @@ func (c *Campaign) AnonymizeByID(
|
||||
c.Logger.Errorw("failed to get campaign recipients by campaign id", "error", err)
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
for _, cr := range campaignRecipients {
|
||||
for _, cr := range campaignRecipientsResult.Rows {
|
||||
if cr.RecipientID.IsNull() {
|
||||
c.Logger.Debug("skipping anonymization of campaign recipient without recipient")
|
||||
continue
|
||||
@@ -3224,17 +3224,17 @@ func (c *Campaign) AnonymizeByID(
|
||||
anonymizedID := uuid.New()
|
||||
cr.AnonymizedID = nullable.NewNullableWithValue(anonymizedID)
|
||||
recipientID := cr.RecipientID.MustGet()
|
||||
err := c.CampaignRecipientRepository.Anonymize(ctx, &recipientID, &anonymizedID)
|
||||
if err != nil {
|
||||
c.Logger.Errorw("failed to add anonymized ID to campaign recipient", "error", err)
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
// anonymize events and assign each anonymized ID so the events can still be tracked
|
||||
campaignID, err := cr.CampaignID.Get()
|
||||
if err != nil {
|
||||
c.Logger.Debug("Recipient removed or anonymized, skipping in anonymization")
|
||||
continue
|
||||
}
|
||||
err = c.CampaignRecipientRepository.Anonymize(ctx, &campaignID, &recipientID, &anonymizedID)
|
||||
if err != nil {
|
||||
c.Logger.Errorw("failed to add anonymized ID to campaign recipient", "error", err)
|
||||
return errs.Wrap(err)
|
||||
}
|
||||
// anonymize events and assign each anonymized ID so the events can still be tracked
|
||||
err = c.CampaignRepository.AnonymizeCampaignEvent(
|
||||
ctx,
|
||||
&campaignID,
|
||||
|
||||
@@ -620,6 +620,7 @@ func (r *Recipient) DeleteByID(
|
||||
anonymizedID := uuid.New()
|
||||
err = r.CampaignRecipientRepository.Anonymize(
|
||||
ctx,
|
||||
nil, // nil campaignID means anonymize across all campaigns
|
||||
id,
|
||||
&anonymizedID,
|
||||
)
|
||||
|
||||
@@ -470,6 +470,7 @@ func (r *RecipientGroup) RemoveRecipients(
|
||||
anonymizedID := uuid.New()
|
||||
err = r.RecipientService.CampaignRecipientRepository.Anonymize(
|
||||
ctx,
|
||||
nil, // nil campaignID means anonymize across all campaigns
|
||||
recpID,
|
||||
&anonymizedID,
|
||||
)
|
||||
@@ -547,6 +548,7 @@ func (r *RecipientGroup) DeleteByID(
|
||||
}
|
||||
err = r.RecipientService.CampaignRecipientRepository.Anonymize(
|
||||
ctx,
|
||||
nil, // nil campaignID means anonymize across all campaigns
|
||||
&recpID,
|
||||
&anonymizedID,
|
||||
)
|
||||
|
||||
@@ -75,6 +75,8 @@
|
||||
};
|
||||
let allowedFilter = null;
|
||||
let campaignRecipients = [];
|
||||
let campaignRecipientsHasNextPage = false;
|
||||
let campaignEventsHasNextPage = false;
|
||||
let recipientEventsRecipient = {
|
||||
name: null,
|
||||
id: null
|
||||
@@ -280,7 +282,7 @@
|
||||
if (!res.success) {
|
||||
throw res.error;
|
||||
}
|
||||
const events = res.data.map((v) => ({
|
||||
const events = (res.data?.rows ?? []).map((v) => ({
|
||||
createdAt: v.sendAt,
|
||||
eventName: 'campaign_recipient_scheduled',
|
||||
recipient: v.recipient
|
||||
@@ -732,7 +734,8 @@
|
||||
if (!res.success) {
|
||||
throw res.error;
|
||||
}
|
||||
campaignRecipients = res.data;
|
||||
campaignRecipients = res.data?.rows ?? [];
|
||||
campaignRecipientsHasNextPage = res.data?.hasNextPage ?? false;
|
||||
} catch (e) {
|
||||
addToast('Failed to load recipients', 'Error');
|
||||
console.error('failed to load recipients', e);
|
||||
@@ -759,7 +762,8 @@
|
||||
eventsTableURLParams
|
||||
);
|
||||
if (res.success) {
|
||||
campaign = { ...campaign, events: res.data.rows };
|
||||
campaign = { ...campaign, events: res.data?.rows ?? [] };
|
||||
campaignEventsHasNextPage = res.data?.hasNextPage ?? false;
|
||||
}
|
||||
} catch (e) {
|
||||
addToast('Failed to load events', 'Error');
|
||||
@@ -1518,6 +1522,7 @@
|
||||
pagination={eventsTableURLParams}
|
||||
plural="events"
|
||||
hasData={!!campaign.events.length}
|
||||
hasNextPage={campaignEventsHasNextPage}
|
||||
hasActions={false}
|
||||
isGhost={isEventTableLoading}
|
||||
>
|
||||
@@ -1603,6 +1608,7 @@
|
||||
pagination={recipientTableUrlParams}
|
||||
plural="recipients"
|
||||
hasData={!!campaignRecipients.length}
|
||||
hasNextPage={campaignRecipientsHasNextPage}
|
||||
isGhost={isRecipientTableLoading}
|
||||
>
|
||||
{#each campaignRecipients as recp (recp.id)}
|
||||
|
||||
Reference in New Issue
Block a user