Skip to content

Commit

Permalink
Merge pull request #3947 from hotosm/develop
Browse files Browse the repository at this point in the history
v4.2.2 Release
  • Loading branch information
willemarcel authored Dec 1, 2020
2 parents 70e0a90 + d095983 commit a9ad143
Show file tree
Hide file tree
Showing 77 changed files with 1,912 additions and 1,391 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ workflows:
branches:
only:
- develop
- staging-test
requires:
- build
stack_name: "staging"
Expand All @@ -243,6 +244,7 @@ workflows:
branches:
only:
- develop
- staging-test
requires:
- build
context: tasking-manager-staging
Expand Down
2 changes: 1 addition & 1 deletion backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def sentry_init():


def format_url(endpoint):
parts = "/".join([i for i in endpoint.split("/") if i])
parts = endpoint.strip("/")
return "/api/{}/{}/".format(EnvironmentConfig.API_VERSION, parts)


Expand Down
5 changes: 3 additions & 2 deletions backend/api/organisations/campaigns.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from backend.services.campaign_service import CampaignService
from backend.services.organisation_service import OrganisationService
from backend.models.postgis.utils import NotFound
from backend.models.postgis.campaign import Campaign
from backend.services.users.authentication_service import token_auth


Expand Down Expand Up @@ -52,7 +51,9 @@ def post(self, organisation_id, campaign_id):
if OrganisationService.can_user_manage_organisation(
organisation_id, token_auth.current_user()
):
if Campaign.campaign_organisation_exists(campaign_id, organisation_id):
if CampaignService.campaign_organisation_exists(
campaign_id, organisation_id
):
message = (
"Campaign {} is already assigned to organisation {}.".format(
campaign_id, organisation_id
Expand Down
10 changes: 5 additions & 5 deletions backend/api/organisations/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def post(self):
default: HOT
logo:
type: string
default: https://tasks.hotosm.org/assets/img/hot-tm-logo.svg
default: https://cdn.hotosm.org/tasking-manager/uploads/1588741335578_hot-logo.png
url:
type: string
default: https://hotosm.org
Expand All @@ -53,8 +53,8 @@ def post(self):
items:
type: string
default: [
the_node_less_traveled,
the_node_less_traveled_import
user_1,
user_2
]
responses:
201:
Expand Down Expand Up @@ -239,8 +239,8 @@ def patch(self, organisation_id):
items:
type: string
default: [
the_node_less_traveled,
the_node_less_traveled_import
user_1,
user_2
]
responses:
201:
Expand Down
8 changes: 8 additions & 0 deletions backend/api/projects/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,9 @@ def setup_search_dto(self):
search_dto.mapping_types = map(
str, mapping_types_str.split(",")
) # Extract list from string
search_dto.mapping_types_exact = strtobool(
request.args.get("mappingTypesExact", "false")
)
project_statuses_str = request.args.get("projectStatuses")
if project_statuses_str:
search_dto.project_statuses = map(str, project_statuses_str.split(","))
Expand Down Expand Up @@ -569,6 +572,11 @@ def get(self):
- in: query
name: mappingTypes
type: string
- in: query
name: mappingTypesExact
type: boolean
default: false
description: if true, limits projects to match the exact mapping types requested
- in: query
name: organisationName
description: Organisation name to search for
Expand Down
2 changes: 1 addition & 1 deletion backend/api/system/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def get(self):
properties:
userName:
type: string
default: the_node_less_traveled
default: user_1
function:
type: string
default: MANAGER
Expand Down
2 changes: 1 addition & 1 deletion backend/models/dtos/project_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ class CustomEditorDTO(Model):
name = StringType(required=True)
description = StringType()
url = StringType(required=True)
enabled = BooleanType(default=False)


class ProjectDTO(Model):
Expand Down Expand Up @@ -291,6 +290,7 @@ class ProjectSearchDTO(Model):
preferred_locale = StringType(default="en")
mapper_level = StringType(validators=[is_known_mapping_level])
mapping_types = ListType(StringType, validators=[is_known_mapping_type])
mapping_types_exact = BooleanType(required=False)
project_statuses = ListType(StringType, validators=[is_known_project_status])
organisation_name = StringType()
organisation_id = IntType()
Expand Down
73 changes: 13 additions & 60 deletions backend/models/postgis/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,66 +52,6 @@ def update(self, dto: CampaignDTO):
self.description = dto.description if dto.description else self.description
db.session.commit()

@staticmethod
def get_all_campaigns() -> CampaignListDTO:
query = Campaign.query.order_by(Campaign.name).distinct()
campaign_list_dto = CampaignListDTO()
for campaign in query:
campaign_dto = CampaignDTO()
campaign_dto.id = campaign.id
campaign_dto.name = campaign.name

campaign_list_dto.campaigns.append(campaign_dto)

return campaign_list_dto

@staticmethod
def get_project_campaigns_as_dto(project_id: int) -> CampaignListDTO:

query = (
Campaign.query.join(campaign_projects)
.filter(campaign_projects.c.project_id == project_id)
.all()
)
campaign_list_dto = CampaignListDTO()
for campaign in query:
campaign_dto = CampaignDTO()
campaign_dto.id = campaign.id
campaign_dto.name = campaign.name

campaign_list_dto.campaigns.append(campaign_dto)

return campaign_list_dto

@staticmethod
def campaign_organisation_exists(campaign_id: int, org_id: int):
return (
Campaign.query.join(campaign_organisations)
.filter(
campaign_organisations.c.organisation_id == org_id,
campaign_organisations.c.campaign_id == campaign_id,
)
.one_or_none()
)

@staticmethod
def get_organisation_campaigns_as_dto(org_id: int) -> CampaignListDTO:

query = (
Campaign.query.join(campaign_organisations)
.filter(campaign_organisations.c.organisation_id == org_id)
.all()
)
campaign_list_dto = CampaignListDTO()
for campaign in query:
campaign_dto = CampaignDTO()
campaign_dto.id = campaign.id
campaign_dto.name = campaign.name

campaign_list_dto.campaigns.append(campaign_dto)

return campaign_list_dto

@classmethod
def from_dto(cls, dto: CampaignDTO):
""" Creates new message from DTO """
Expand All @@ -133,3 +73,16 @@ def as_dto(self) -> CampaignDTO:
campaign_dto.description = self.description

return campaign_dto

@staticmethod
def campaign_list_as_dto(campaigns: list) -> CampaignListDTO:
""" Converts a collection of campaigns into DTO"""
campaign_list_dto = CampaignListDTO()
for campaign in campaigns:
campaign_dto = CampaignDTO()
campaign_dto.id = campaign.id
campaign_dto.name = campaign.name

campaign_list_dto.campaigns.append(campaign_dto)

return campaign_list_dto
3 changes: 0 additions & 3 deletions backend/models/postgis/custom_editors.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class CustomEditor(db.Model):
name = db.Column(db.String(50), nullable=False)
description = db.Column(db.String)
url = db.Column(db.String, nullable=False)
enabled = db.Column(db.Boolean, nullable=False, default=False)

@staticmethod
def get_by_project_id(project_id: int):
Expand All @@ -30,7 +29,6 @@ def update_editor(self, dto: CustomEditorDTO):
self.name = dto.name
self.description = dto.description
self.url = dto.url
self.enabled = dto.enabled

def delete(self):
""" Deletes the current model from the DB """
Expand All @@ -44,6 +42,5 @@ def as_dto(self) -> CustomEditorDTO:
dto.name = self.name
dto.description = self.description
dto.url = self.url
dto.enabled = self.enabled

return dto
58 changes: 30 additions & 28 deletions backend/services/campaign_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from backend.models.postgis.project import Project
from backend.models.postgis.organisation import Organisation
from backend.services.organisation_service import OrganisationService
from backend.models.dtos.organisation_dto import OrganisationDTO


class CampaignService:
Expand All @@ -41,42 +40,26 @@ def delete_campaign(campaign_id: int):
def get_campaign_as_dto(campaign_id: int, user_id: int):
"""Gets the specified campaign"""
campaign = CampaignService.get_campaign(campaign_id)

campaign_dto = CampaignDTO()
campaign_dto.id = campaign.id
campaign_dto.url = campaign.url
campaign_dto.name = campaign.name
campaign_dto.logo = campaign.logo
campaign_dto.description = campaign.description
campaign_dto.organisations = []

orgs = (
Organisation.query.join(campaign_organisations)
.filter(campaign_organisations.c.campaign_id == campaign.id)
.all()
)

for org in orgs:
if user_id != 0:
logged_in = OrganisationService.can_user_manage_organisation(
org.id, user_id
)
else:
logged_in = False

organisation_dto = OrganisationDTO()

organisation_dto.organisation_id = org.id
organisation_dto.name = org.name
organisation_dto.logo = org.logo
organisation_dto.url = org.url
organisation_dto.is_manager = logged_in

return campaign_dto

@staticmethod
def get_project_campaigns_as_dto(project_id: int) -> CampaignListDTO:
"""Gets all the campaigns for a specified project"""
return Campaign.get_project_campaigns_as_dto(project_id)
query = (
Campaign.query.join(campaign_projects)
.filter(campaign_projects.c.project_id == project_id)
.all()
)

return Campaign.campaign_list_as_dto(query)

@staticmethod
def delete_project_campaign(project_id: int, campaign_id: int):
Expand All @@ -90,11 +73,14 @@ def delete_project_campaign(project_id: int, campaign_id: int):

@staticmethod
def get_all_campaigns() -> CampaignListDTO:
"""List all campaigns"""
return Campaign.get_all_campaigns()
""" Returns a list of all campaigns """
query = Campaign.query.order_by(Campaign.name).distinct()

return Campaign.campaign_list_as_dto(query)

@staticmethod
def create_campaign(campaign_dto: NewCampaignDTO):
""" Creates a new campaign """
campaign = Campaign.from_dto(campaign_dto)
try:
campaign.create()
Expand Down Expand Up @@ -136,7 +122,23 @@ def create_campaign_organisation(organisation_id: int, campaign_id: int):
@staticmethod
def get_organisation_campaigns_as_dto(organisation_id: int) -> CampaignListDTO:
""" Gets all the campaigns for a specified project """
return Campaign.get_organisation_campaigns_as_dto(organisation_id)
query = (
Campaign.query.join(campaign_organisations)
.filter(campaign_organisations.c.organisation_id == organisation_id)
.all()
)
return Campaign.campaign_list_as_dto(query)

@staticmethod
def campaign_organisation_exists(campaign_id: int, org_id: int):
return (
Campaign.query.join(campaign_organisations)
.filter(
campaign_organisations.c.organisation_id == org_id,
campaign_organisations.c.campaign_id == campaign_id,
)
.one_or_none()
)

@staticmethod
def delete_organisation_campaign(organisation_id: int, campaign_id: int):
Expand Down
32 changes: 32 additions & 0 deletions backend/services/organisation_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
ListOrganisationsDTO,
UpdateOrganisationDTO,
)
from backend.models.postgis.campaign import campaign_organisations
from backend.models.postgis.organisation import Organisation
from backend.models.postgis.project import Project, ProjectInfo
from backend.models.postgis.utils import NotFound
Expand Down Expand Up @@ -207,3 +208,34 @@ def is_user_an_org_manager(organisation_id: int, user_id: int):
user = UserService.get_user_by_id(user_id)

return user in org.managers

@staticmethod
def get_campaign_organisations_as_dto(campaign_id: int, user_id: int):
"""
Returns organisations under a particular campaign
"""
organisation_list_dto = ListOrganisationsDTO()
orgs = (
Organisation.query.join(campaign_organisations)
.filter(campaign_organisations.c.campaign_id == campaign_id)
.all()
)

for org in orgs:
if user_id != 0:
logged_in = OrganisationService.can_user_manage_organisation(
org.id, user_id
)
else:
logged_in = False

organisation_dto = OrganisationDTO()
organisation_dto.organisation_id = org.id
organisation_dto.name = org.name
organisation_dto.logo = org.logo
organisation_dto.url = org.url
organisation_dto.is_manager = logged_in

organisation_list_dto.organisations.append(organisation_dto)

return organisation_list_dto
19 changes: 14 additions & 5 deletions backend/services/project_search_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,21 @@ def _filter_projects(search_dto: ProjectSearchDTO, user):
if search_dto.mapping_types:
# Construct array of mapping types for query
mapping_type_array = []
mapping_type_array = [
MappingTypes[mapping_type].value
for mapping_type in search_dto.mapping_types
]

query = query.filter(Project.mapping_types.contains(mapping_type_array))
if search_dto.mapping_types_exact:
mapping_type_array = [
{
MappingTypes[mapping_type].value
for mapping_type in search_dto.mapping_types
}
]
query = query.filter(Project.mapping_types.in_(mapping_type_array))
else:
mapping_type_array = [
MappingTypes[mapping_type].value
for mapping_type in search_dto.mapping_types
]
query = query.filter(Project.mapping_types.overlap(mapping_type_array))

if search_dto.text_search:
# We construct an OR search, so any projects that contain or more of the search terms should be returned
Expand Down
Loading

0 comments on commit a9ad143

Please sign in to comment.