Source code for challengeutils.createchallenge

"""The skeleton for two challenges site with initial wiki, four teams
(admin, participants, organizers, and preregistrants), and
a challenge widget added on live site with a participant
team associated with it.

For more information on challenges administration:
https://docs.synapse.org/articles/challenge_administration.html

Example::

    import challengeutils
    import synapseclient
    syn = synapseclient.login()
    challengeutils.createchallenge.main(syn, "Plouf Challenge")

"""
import logging
import sys

import synapseclient
from synapseclient.core.exceptions import SynapseHTTPError
import synapseutils

from . import challenge, permissions, utils

logger = logging.getLogger(__name__)

# TODO: Add participants
# A pre-defined wiki project is used as initial template for challenge sites.
# To copy over the template synapseutils.copyWiki() function is used with
# template id as source and new challenge project entity synId as destination.
# DREAM_CHALLENGE_TEMPLATE_SYNID = "syn2769515"  # Template 1.0
DREAM_CHALLENGE_TEMPLATE_SYNID = "syn18058986"  # Template 2.0

LIVE_PAGE_MARKDOWN = (
    "## Banner\n\n"
    "{row}\n {column width=2}\n "
    "{column}\n {column width=4}\n"
    "#### ${jointeam?teamId=%s&isChallenge=false&isMemberMessage=You have successfully preregistered for the challenge&text=Click here to preregister&isSimpleRequestButton=true&requestOpenText=Your registration is in progress&successMessage=Your registration is in progress}\n "
    "{column}\n {column width=5}\n"
    "###! There are ${teammembercount?teamId=%s} preregistered participants. <br>**Join them now!**\n "
    "{column}\n {column width=1}\n "
    "{column}\n{row}\n"
    "\n---\n\n"
    "## Overview\n\n<font size=4>**Goal:**</font>\n\n<font size=4>**Motivation:**</font>\n"
    "\n---\n\n"
    "## Timeline\n\n"
    "\n---\n\n"
    "## Challenge Organizers\n\n"
    "\n---\n\n"
    "## Funders/Sponsors/Data Contributors/Journal Partners:\n\n"
)


[docs]def create_project(syn, project_name): """Creates Synapse Project Args: syn: Synpase object project_name: Name of project Returns: Project Entity """ project = synapseclient.Project(project_name) # returns the handle to the project if the user has sufficient priviledge project = syn.store(project) logger.info("Created/Fetched Project {} ({})".format(project.name, project.id)) return project
[docs]def create_team(syn, team_name, desc, can_public_join=False): """Creates Synapse Team Args: syn: Synpase object team_name: Name of team desc: Description of team can_public_join: true for teams which members can join without an invitation or approval. Default to False Returns: Synapse Team id """ try: # raises a ValueError if a team does not exist team = syn.getTeam(team_name) logger.info("The team {} already exists.".format(team_name)) logger.info(team) # If you press enter, this will default to 'y' user_input = input("Do you want to use this team? (Y/n) ") or "y" if user_input.lower() not in ("y", "yes"): logger.info("Please specify a new challenge name. Exiting.") sys.exit(1) except ValueError: team = synapseclient.Team( name=team_name, description=desc, canPublicJoin=can_public_join ) # raises a ValueError if a team with this name already exists team = syn.store(team) logger.info("Created Team {} ({})".format(team.name, team.id)) return team
[docs]def create_evaluation_queue(syn, name, description, parentid): """ Creates Evaluation Queues Args: syn: Synpase object name: Name of evaluation queue description: Description of queue parentid: Synapse project id Returns: Evalation Queue """ queue_ent = synapseclient.Evaluation( name=name, description=description, contentSource=parentid ) queue = syn.store(queue_ent) logger.info("Created Queue {}({})".format(queue.name, queue.id)) return queue
def _create_live_wiki(syn, project, teamid): """Creates the wiki of the live challenge page Args: syn: Synpase object project: Synapse project teamid: Synapse team id of participant team """ markdown = LIVE_PAGE_MARKDOWN % (teamid, teamid) syn.store(synapseclient.Wiki(title="", owner=project, markdown=markdown))
[docs]def create_challenge_widget(syn, project_live, team_part_id): """Creates challenge widget - activates a Synapse project If challenge object exists, it retrieves existing object Args: syn: Synpase object project_live: Synapse id of live challenge project team_part_id: Synapse team id of participant team """ try: chal_obj = challenge.create_challenge(syn, project_live, team_part_id) logger.info("Created Challenge ({})".format(chal_obj.id)) except SynapseHTTPError: chal_obj = challenge.get_challenge(syn, project_live) logger.info("Fetched existing Challenge ({})".format(chal_obj.id)) return chal_obj
def _update_wikipage_string( wikipage_string, challengeid, teamid, challenge_name, synid ): """Updates wikipage strings in the challenge wiki template with the newly created challengeid, teamid, challenge name and project id Args: wikipage_string: Original wikipage string challengeid: New challenge id teamid: Synapse Team id challenge_name: challenge name synid: Synapse id of project Returns: fixed wiki page string """ wikipage_string = wikipage_string.replace( "challengeId=0", "challengeId=%s" % challengeid ) wikipage_string = wikipage_string.replace("{teamId}", teamid) wikipage_string = wikipage_string.replace("teamId=0", "teamId=%s" % teamid) wikipage_string = wikipage_string.replace("#!Map:0", "#!Map:%s" % teamid) wikipage_string = wikipage_string.replace("{challengeName}", challenge_name) wikipage_string = wikipage_string.replace("projectId=syn0", "projectId=%s" % synid) return wikipage_string def _create_teams(syn, challenge_name): """Create teams needed for a challenge: participant, admin, organizer, and preregistration team Args: syn: Synapse connection challenge_name: Name of the challenge Returns: dict of challenge team ids """ team_part = challenge_name + " Participants" team_admin = challenge_name + " Admin" team_prereg = challenge_name + " Preregistrants" # The organizer team is used to gate permissions # The motivation is that not everyone needs admin access to the projects team_org = challenge_name + " Organizers" team_part_ent = create_team( syn, team_part, "Challenge Particpant Team", can_public_join=True ) team_admin_ent = create_team( syn, team_admin, "Challenge Admin Team", can_public_join=False ) team_org_ent = create_team( syn, team_org, "Challenge Organizing Team", can_public_join=False ) team_prereg_ent = create_team( syn, team_prereg, "Challenge Pre-registration Team", can_public_join=True ) team_map = { "team_part_id": team_part_ent["id"], "team_admin_id": team_admin_ent["id"], "team_prereg_id": team_prereg_ent["id"], "team_org_id": team_org_ent["id"], } return team_map
[docs]def check_existing_and_delete_wiki(syn, synid): """Checks if wiki exists, and if so prompt to delete Args: syn: Synapse connection synid: Synapse id of an Entity """ wiki = None try: wiki = syn.getWiki(synid) except SynapseHTTPError: pass if wiki is not None: logger.info("The staging project has already a wiki.") logger.info(wiki) user_input = ( input("Do you agree to delete the wiki before continuing? (y/N) ") or "n" ) if user_input.lower() not in ("y", "yes"): logger.info("Exiting") sys.exit(1) else: logger.info("Deleting wiki of the staging project ({})".format(wiki.id)) syn.delete(wiki)
[docs]def main(syn, challenge_name, live_site=None): """Creates two project entity for challenge sites. 1) live (public) and 2) staging (private until launch) Allow for users to set up the live site themselves Args: syn: Synapse object challenge_name: Name of the challenge live_site: If there is already a live site, specify live site Synapse id. (Default is None) Returns: dict:: { "live_projectid": projectid, "staging_projectid": projectid, "admin_teamid": teams['team_admin_id'], "organizer_teamid": teams['team_org_id'], "participant_teamid": teams['team_part_id'], "preregistrantrant_teamid": teams['team_prereg_id'] } """ # Create teams for challenge sites teams = _create_teams(syn, challenge_name) # Create live Project if live_site is None: project_live = create_project(syn, challenge_name) permissions.set_entity_permissions( syn, project_live, teams["team_admin_id"], permission_level="admin" ) permissions.set_entity_permissions( syn, project_live, teams["team_org_id"], permission_level="moderate" ) _create_live_wiki(syn, project_live, teams["team_prereg_id"]) else: project_live = syn.get(live_site) challenge_obj = create_challenge_widget(syn, project_live, teams["team_part_id"]) create_evaluation_queue( syn, "%s Project Submission" % challenge_name, "Project Submission", project_live.id, ) # Create staging Project project_staging = create_project(syn, challenge_name + " - staging") permissions.set_entity_permissions( syn, project_staging, teams["team_admin_id"], permission_level="admin" ) permissions.set_entity_permissions( syn, project_staging, teams["team_org_id"], permission_level="edit" ) # Checks if staging wiki exists, if so delete check_existing_and_delete_wiki(syn, project_staging.id) logger.info("Copying wiki template to {}".format(project_staging.name)) new_wikiids = synapseutils.copyWiki( syn, DREAM_CHALLENGE_TEMPLATE_SYNID, project_staging.id ) for page in new_wikiids: wikipage = syn.getWiki(project_staging, page["id"]) wikipage.markdown = _update_wikipage_string( wikipage.markdown, challenge_obj.id, teams["team_part_id"], challenge_name, project_live.id, ) syn.store(wikipage) return { "live_projectid": project_live.id, "staging_projectid": project_staging.id, "admin_teamid": teams["team_admin_id"], "organizer_teamid": teams["team_org_id"], "participant_teamid": teams["team_part_id"], "preregistrantrant_teamid": teams["team_prereg_id"], }