mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-10-12 01:58:53 +02:00
added awareness training campaign mode, report, template mode, and stats
Signed-off-by: RonniSkansing <rskansing@gmail.com>
This commit is contained in:
1 parent
6804710d3c
commit
a7fbd573f6
37 files changed
+1540
-233
No files matched your search
@@ -72,6 +72,10 @@ type Campaign struct {
|
||||
LureCodeAlgo string `gorm:"not null;default:'crockford32'"`
|
||||
LureCodeLength int `gorm:"not null;default:12"`
|
||||
|
||||
// IsTraining marks the campaign as an awareness training campaign. Snapshotted
|
||||
// from the template at create time so stats and risk queries filter on it here.
|
||||
IsTraining bool `gorm:"not null;default:false;index"`
|
||||
|
||||
// has one
|
||||
CampaignTemplateID *uuid.UUID `gorm:"index;type:uuid;"`
|
||||
CampaignTemplate *CampaignTemplate
|
||||
|
||||
@@ -37,9 +37,16 @@ type CampaignStats struct {
|
||||
DataSubmissions int `gorm:"not null;default:0" json:"dataSubmissions"` // Form submissions
|
||||
Reported int `gorm:"not null;default:0" json:"reported"` // Reported phishing
|
||||
|
||||
// Training funnel, populated for training campaigns only
|
||||
TrainingStarted int `gorm:"not null;default:0" json:"trainingStarted"`
|
||||
TrainingCompleted int `gorm:"not null;default:0" json:"trainingCompleted"`
|
||||
|
||||
// Campaign metadata
|
||||
TemplateName string `gorm:"" json:"templateName"`
|
||||
CampaignType string `gorm:"" json:"campaignType"` // 'scheduled', 'self-managed'
|
||||
// IsTraining marks the snapshot as an awareness training campaign so phishing
|
||||
// trend charts can exclude it from failure rate calculations.
|
||||
IsTraining bool `gorm:"not null;default:false" json:"isTraining"`
|
||||
}
|
||||
|
||||
func (CampaignStats) TableName() string {
|
||||
|
||||
@@ -36,6 +36,10 @@ type CampaignTemplate struct {
|
||||
// data such as domainID, landingPage and etc to be used in a campaign
|
||||
IsUsable bool `gorm:"not null;default:false;index"`
|
||||
|
||||
// IsTraining marks the template as an awareness training template. Campaigns
|
||||
// built from it emit training events instead of phishing page visit events.
|
||||
IsTraining bool `gorm:"not null;default:false;index"`
|
||||
|
||||
// has-a
|
||||
LandingPageID *uuid.UUID `gorm:"type:uuid;index;"`
|
||||
LandingPage *Page `gorm:"references:LandingPage;foreignKey:LandingPageID;references:ID;"`
|
||||
|
||||
@@ -18,7 +18,7 @@ type CampaignWebhook struct {
|
||||
// values: "none", "basic", "full"
|
||||
WebhookIncludeData string `gorm:"not null;default:'full'"`
|
||||
|
||||
// webhookevents is a binary format storing selected events as bits (10 events)
|
||||
// webhookevents is a binary format storing selected events as bits (12 events)
|
||||
// 0 = all events (default, backward compatible)
|
||||
// non-zero = only selected events trigger webhooks
|
||||
// bit 0 (1): campaign_closed
|
||||
@@ -31,6 +31,8 @@ type CampaignWebhook struct {
|
||||
// bit 7 (128): campaign_recipient_page_visited
|
||||
// bit 8 (256): campaign_recipient_after_page_visited
|
||||
// bit 9 (512): campaign_recipient_deny_page_visited
|
||||
// bit 10 (1024): campaign_recipient_training_started
|
||||
// bit 11 (2048): campaign_recipient_training_completed
|
||||
WebhookEvents int `gorm:"not null;default:0"`
|
||||
}
|
||||
|
||||
|
||||
@@ -16,15 +16,28 @@ type ReportTemplate struct {
|
||||
ID *uuid.UUID `gorm:"primary_key;not null;unique;type:uuid"`
|
||||
CreatedAt *time.Time `gorm:"not null;index;"`
|
||||
UpdatedAt *time.Time `gorm:"not null;index"`
|
||||
CompanyID *uuid.UUID `gorm:"uniqueIndex;type:uuid"`
|
||||
CompanyID *uuid.UUID `gorm:"type:uuid"`
|
||||
Content string `gorm:"not null;type:text"`
|
||||
|
||||
// IsTraining selects the report used for awareness training campaigns, so a
|
||||
// company can hold a separate phishing and training report template. Uniqueness
|
||||
// is enforced per kind by the indexes in Migrate.
|
||||
IsTraining bool `gorm:"not null;default:false"`
|
||||
|
||||
Company *Company
|
||||
}
|
||||
|
||||
func (e *ReportTemplate) Migrate(db *gorm.DB) error {
|
||||
// enforce at most one global template (company_id IS NULL)
|
||||
idx := `CREATE UNIQUE INDEX IF NOT EXISTS idx_report_templates_null_company_id ON report_templates ((company_id IS NULL)) WHERE (company_id IS NULL)`
|
||||
// drop the legacy indexes that enforced one template per company and one global,
|
||||
// replaced by the per kind indexes below
|
||||
db.Exec(`DROP INDEX IF EXISTS idx_report_templates_company_id`)
|
||||
db.Exec(`DROP INDEX IF EXISTS idx_report_templates_null_company_id`)
|
||||
// one template per company per kind (the global case is covered separately)
|
||||
if err := db.Exec(`CREATE UNIQUE INDEX IF NOT EXISTS idx_report_templates_company_training ON report_templates(company_id, is_training) WHERE company_id IS NOT NULL`).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
// enforce at most one global template per kind (company_id IS NULL)
|
||||
idx := `CREATE UNIQUE INDEX IF NOT EXISTS idx_report_templates_null_company_training ON report_templates(is_training) WHERE company_id IS NULL`
|
||||
return db.Exec(idx).Error
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user