Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Campaigns & Leads #400

Merged
merged 5 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
31 changes: 31 additions & 0 deletions microsetta_private_api/admin/admin_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from microsetta_private_api.repo.source_repo import SourceRepo
from microsetta_private_api.repo.transaction import Transaction
from microsetta_private_api.repo.admin_repo import AdminRepo
from microsetta_private_api.repo.campaign_repo import CampaignRepo
from microsetta_private_api.repo.metadata_repo import retrieve_metadata
from microsetta_private_api.tasks import send_email as celery_send_email,\
per_sample_summary as celery_per_sample_summary
Expand Down Expand Up @@ -522,6 +523,36 @@ def address_verification(token_info, address_1, address_2=None, city=None,
return jsonify(melissa_response), 200


def list_campaigns(token_info):
validate_admin_access(token_info)

with Transaction() as t:
campaign_repo = CampaignRepo(t)
campaigns = campaign_repo.get_all_campaigns()
return jsonify(campaigns), 200


def post_campaign_information(body, token_info):
validate_admin_access(token_info)

with Transaction() as t:
campaign_repo = CampaignRepo(t)

if 'campaign_id' in body:
try:
res = campaign_repo.update_campaign(**body)
except ValueError as e:
raise RepoException(e)
else:
try:
res = campaign_repo.create_campaign(**body)
except ValueError as e:
raise RepoException(e)

t.commit()
return jsonify(res), 200


def generate_activation_codes(body, token_info):
validate_admin_access(token_info)

Expand Down
7 changes: 6 additions & 1 deletion microsetta_private_api/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
check_activation
)

from ._campaign import (
get_campaign_information
)

__all__ = [
'find_accounts_for_login',
'register_account',
Expand Down Expand Up @@ -55,5 +59,6 @@
'submit_answered_survey',
'verify_jwt',
'get_preparations',
'check_activation'
'check_activation',
'get_campaign_information'
]
16 changes: 16 additions & 0 deletions microsetta_private_api/api/_campaign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from flask import jsonify
from microsetta_private_api.repo.campaign_repo import CampaignRepo
from microsetta_private_api.repo.transaction import Transaction


def get_campaign_information(campaign_id):
with Transaction() as t:
campaign_repo = CampaignRepo(t)
campaign = campaign_repo.get_campaign_by_id(campaign_id)

# rather than return an error on a bad campaign id, we'll return
# a code indicating that so the signup form can handle it gracefully
if campaign is None:
return jsonify(campaign_id="BADID"), 200
wasade marked this conversation as resolved.
Show resolved Hide resolved
else:
return campaign, 200
90 changes: 90 additions & 0 deletions microsetta_private_api/api/microsetta_private_api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,79 @@ paths:
type: string
nullable: true

'/campaign_information':
get:
operationId: microsetta_private_api.api.get_campaign_information
tags:
- Campaigns
summary: Get campaign information based on provided campaign_id
description: Get campaign information based on provided campaign_id
security: []
parameters:
- in: query
name: campaign_id
description: unique identifier of campaign to get information for
required: true
schema:
type: string
responses:
'200':
description: campaign information
content:
application/json:
schema:
type: object
'404':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the 404 be removed?

$ref: '#/components/responses/404NotFound'
post:
operationId: microsetta_private_api.admin.admin_impl.post_campaign_information
tags:
- Campaigns
- Admin
summary: Create or update campaign information
description: Create or update campaign information
requestBody:
content:
application/json:
schema:
type: object
properties:
'campaign_id':
type: string
'title':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these are required fields, and if not provided, will result in a 500 error. Can the required fields be noted? see the endpoint associated with microsetta_private_api.api.create_human_source_from_consent as an example

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After looking at it, the only field that's globally required - and therefore can be in the API as such - is title. campaign_id is only required on updates and associated_projects is only required on creation. I could break it into two separate api paths if you prefer, but that might be overkill.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be more consistent w/ the rest of the API for creation to be POST and update to be PUT, but against the same endpoint. Does that make sense?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, will adjust in a few minutes.

type: string
'instructions':
type: string
'permitted_countries':
type: string
'language_key':
type: string
'accepting_participants':
type: string
'associated_projects':
type: string
'language_key_alt':
type: string
'title_alt':
type: string
'instructions_alt':
type: string
'extension':
type: string
responses:
'200':
description: campaign information
content:
application/json:
schema:
type: object
'401':
$ref: '#/components/responses/401Unauthorized'
'403':
$ref: '#/components/responses/403Forbidden'
'404':
$ref: '#/components/responses/404NotFound'


'/preparations/{sample_barcode}':
get:
Expand Down Expand Up @@ -1200,6 +1273,23 @@ paths:
'404':
$ref: '#/components/responses/404NotFound'

'/admin/campaigns/list':
get:
operationId: microsetta_private_api.admin.admin_impl.list_campaigns
tags:
- Admin
summary: Return a list of all campaigns
description: Return a list of all campaigns
responses:
'200':
description: Array of campaigns
content:
application/json:
schema:
type: array
'401':
$ref: '#/components/responses/401Unauthorized'

'/admin/scan/{sample_barcode}':
post:
# Note: We might want to be able to differentiate system administrator operations
Expand Down
47 changes: 47 additions & 0 deletions microsetta_private_api/db/patches/0088.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
CREATE TABLE barcodes.campaigns (
campaign_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
title varchar NOT NULL UNIQUE,
instructions text,
header_image varchar,
permitted_countries text,
language_key varchar,
accepting_participants boolean DEFAULT FALSE,
language_key_alt varchar,
title_alt varchar,
instructions_alt text
);

CREATE TABLE barcodes.interested_users (
interested_user_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
campaign_id uuid NOT NULL,
acquisition_source varchar,
first_name varchar NOT NULL,
last_name varchar NOT NULL,
email varchar NOT NULL,
phone varchar,
address_1 varchar,
address_2 varchar,
city varchar,
state varchar,
postal_code varchar,
country varchar,
latitude double precision,
longitude double precision,
confirm_consent boolean DEFAULT FALSE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
confirm_consent boolean DEFAULT FALSE,
confirm_consent boolean not null DEFAULT FALSE,

ip_address varchar,
creation_timestamp timestamp DEFAULT NOW(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
creation_timestamp timestamp DEFAULT NOW(),
creation_timestamp timestamp not null DEFAULT NOW(),

update_timestamp timestamp,
address_checked boolean DEFAULT FALSE,
address_valid boolean DEFAULT FALSE,
converted_to_account boolean DEFAULT FALSE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
address_checked boolean DEFAULT FALSE,
address_valid boolean DEFAULT FALSE,
converted_to_account boolean DEFAULT FALSE,
address_checked boolean not null DEFAULT FALSE,
address_valid boolean not null DEFAULT FALSE,
converted_to_account boolean not null DEFAULT FALSE,

converted_to_account_timestamp timestamp,
CONSTRAINT fk_campaign_id FOREIGN KEY ( campaign_id ) REFERENCES barcodes.campaigns ( campaign_id )
);

CREATE TABLE barcodes.campaigns_projects (
campaign_id uuid NOT NULL,
project_id bigint NOT NULL,
CONSTRAINT campaign_project_pkey PRIMARY KEY ( campaign_id, project_id ),
CONSTRAINT fk_campaign_id FOREIGN KEY ( campaign_id ) REFERENCES barcodes.campaigns( campaign_id ),
CONSTRAINT fk_project_id FOREIGN KEY ( project_id ) REFERENCES barcodes.project( project_id )
);
34 changes: 34 additions & 0 deletions microsetta_private_api/model/campaign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from microsetta_private_api.model.model_base import ModelBase


class Campaign(ModelBase):
def __init__(self, campaign_id, title, instructions, header_image,
permitted_countries, language_key, accepting_participants,
associated_projects, language_key_alt, title_alt,
instructions_alt):
self.campaign_id = campaign_id
self.title = title
self.instructions = instructions
self.header_image = header_image
self.permitted_countries = permitted_countries
self.language_key = language_key
self.accepting_participants = accepting_participants
self.associated_projects = associated_projects
self.language_key_alt = language_key_alt
self.title_alt = title_alt
self.instructions_alt = instructions_alt

def to_api(self):
return {
"campaign_id": self.campaign_id,
"title": self.title,
"instructions": self.instructions,
"header_image": self.header_image,
"permitted_countries": self.permitted_countries,
"language_key": self.language_key,
"accepting_participants": self.accepting_participants,
"associated_projects": self.associated_projects,
"language_key_alt": self.language_key_alt,
"title_alt": self.title_alt,
"instructions_alt": self.instructions_alt
}
Loading