66from flask import session , request , abort , url_for
77from maproulette .helpers import get_random_task ,\
88 get_challenge_or_404 , get_task_or_404 ,\
9- require_signedin , osmerror , challenge_exists , \
9+ require_signedin , osmerror , \
1010 json_to_task , refine_with_user_area , user_area_is_defined ,\
11- send_email , as_stats_dict
11+ send_email , as_stats_dict , challenge_exists
1212from maproulette .models import Challenge , Task , Action , User , db
1313from geoalchemy2 .functions import ST_Buffer
1414from geoalchemy2 .shape import to_shape
1515from sqlalchemy import func
1616import geojson
1717import json
1818import markdown
19+ import re
1920
2021
2122class ProtectedResource (Resource ):
@@ -175,7 +176,10 @@ def put(self):
175176 abort (400 )
176177 [session .pop (k , None ) for k , v in payload .iteritems () if v is None ]
177178 for k , v in payload .iteritems ():
179+ if k not in me_fields .keys ():
180+ abort (400 , 'you cannot set this key' )
178181 if v is not None :
182+ app .logger .debug ('setting {k} to {v}' .format (k = k , v = v ))
179183 session [k ] = v
180184 return {}
181185
@@ -522,22 +526,48 @@ class AdminApiChallenge(Resource):
522526
523527 """Admin challenge creation endpoint"""
524528
529+ def post (self , slug ):
530+ if challenge_exists (slug ):
531+ abort (409 , 'This challenge already exists' )
532+ if not re .match ("^[\w\d_-]+$" , slug ):
533+ abort (400 , 'slug should contain only a-z, A-Z, 0-9, _, -' )
534+ try :
535+ payload = json .loads (request .data )
536+ except Exception :
537+ abort (400 , "JSON bad" )
538+ if 'title' not in payload :
539+ abort (400 , "new challenge must have title" )
540+ c = Challenge (slug , payload .get ('title' ))
541+ if 'title' in payload :
542+ c .title = payload .get ('title' )
543+ if 'geometry' in payload :
544+ c .geometry = payload .get ('geometry' )
545+ if 'description' in payload :
546+ c .description = payload .get ('description' )
547+ if 'blurb' in payload :
548+ c .blurb = payload .get ('blurb' )
549+ if 'help' in payload :
550+ c .help = payload .get ('help' )
551+ if 'instruction' in payload :
552+ c .instruction = payload .get ('instruction' )
553+ if 'active' in payload :
554+ c .active = payload .get ('active' )
555+ if 'difficulty' in payload :
556+ c .difficulty = payload .get ('difficulty' )
557+ db .session .add (c )
558+ db .session .commit ()
559+ return {}, 201
560+
525561 def put (self , slug ):
526- exists = challenge_exists (slug )
562+ c = get_challenge_or_404 (slug , abort_if_inactive = False )
563+ if not re .match ("^[\w\d_-]+$" , slug ):
564+ abort (400 , 'slug should contain only a-z, A-Z, 0-9, _, -' )
527565 try :
528566 payload = json .loads (request .data )
529567 except Exception :
530568 abort (400 , "JSON bad" )
531- if not exists and 'title' not in payload :
532- abort (400 , "No title" )
533- return {}
534- if exists :
535- app .logger .debug ('challenge existed, retrieving' )
536- c = get_challenge_or_404 (slug , abort_if_inactive = False )
537- if 'title' in payload :
538- c .title = payload .get ('title' )
539- else :
540- c = Challenge (slug , payload .get ('title' ))
569+ if 'title' in payload :
570+ c .title = payload .get ('title' )
541571 if 'geometry' in payload :
542572 c .geometry = payload .get ('geometry' )
543573 if 'description' in payload :
@@ -552,10 +582,9 @@ def put(self, slug):
552582 c .active = payload .get ('active' )
553583 if 'difficulty' in payload :
554584 c .difficulty = payload .get ('difficulty' )
555- merged_c = db .session .merge (c )
556- db .session .add (merged_c )
585+ db .session .add (c )
557586 db .session .commit ()
558- return {}
587+ return {}, 200
559588
560589 def delete (self , slug ):
561590 """delete a challenge"""
@@ -581,16 +610,32 @@ class AdminApiUpdateTask(Resource):
581610
582611 """Challenge Task Create / Update endpoint"""
583612
584- def put (self , slug , identifier ):
585- """Create or update one task."""
613+ def post (self , slug , identifier ):
614+ """create one task."""
615+
616+ if not re .match ("^[\w\d_-]+$" , identifier ):
617+ abort (400 , 'identifier should contain only a-z, A-Z, 0-9, _, -' )
586618
587619 # Parse the posted data
588- t = json_to_task (slug , json .loads (request .data ))
589- merged_t = db .session .merge (t )
590- db .session .add (merged_t )
620+ t = json_to_task (
621+ slug ,
622+ json .loads (request .data ))
623+ db .session .add (t )
591624 db .session .commit ()
592625 return {}, 201
593626
627+ def put (self , slug , identifier ):
628+ """update one task."""
629+
630+ # Parse the posted data
631+ t = json_to_task (
632+ slug ,
633+ json .loads (request .data ),
634+ task = get_task_or_404 (slug , identifier ))
635+ db .session .add (t )
636+ db .session .commit ()
637+ return {}, 200
638+
594639 def delete (self , slug , identifier ):
595640 """Delete a task"""
596641
@@ -606,7 +651,9 @@ class AdminApiUpdateTasks(Resource):
606651
607652 """Bulk task create / update endpoint"""
608653
609- def put (self , slug ):
654+ def post (self , slug ):
655+
656+ """bulk create"""
610657
611658 # Get the posted data
612659 data = json .loads (request .data )
@@ -615,12 +662,44 @@ def put(self, slug):
615662 app .logger .debug ('posting {number} tasks...' .format (number = len (data )))
616663
617664 if len (data ) > app .config ['MAX_TASKS_BULK_UPDATE' ]:
618- abort (400 , 'more than 5000 tasks in bulk update ' )
665+ abort (400 , 'more than 5000 tasks in bulk create ' )
619666
620667 for task in data :
668+ if not 'identifier' in task :
669+ abort (400 , 'task must have identifier' )
670+ if not re .match ("^[\w\d_-]+$" , task ['identifier' ]):
671+ abort (400 , 'identifier should contain only a-z, A-Z, 0-9, _, -' )
672+ if not 'geometries' in task :
673+ abort (400 , 'new task must have geometries' )
621674 t = json_to_task (slug , task )
622- merged_t = db .session .merge (t )
623- db .session .add (merged_t )
675+ db .session .add (t )
676+
677+ # commit all dirty tasks at once.
678+ db .session .commit ()
679+ return {}, 200
680+
681+ def put (self , slug ):
682+
683+ """bulk update"""
684+
685+ # Get the posted data
686+ data = json .loads (request .data )
687+
688+ # debug output number of tasks being posted
689+ app .logger .debug ('putting {number} tasks...' .format (number = len (data )))
690+
691+ if len (data ) > app .config ['MAX_TASKS_BULK_UPDATE' ]:
692+ abort (400 , 'more than 5000 tasks in bulk update' )
693+
694+ for task in data :
695+ if not 'identifier' in task :
696+ abort (400 , 'task must have identifier' )
697+ if not re .match ("^[\w\d_-]+$" , task ['identifier' ]):
698+ abort (400 , 'identifier should contain only a-z, A-Z, 0-9, _, -' )
699+ t = json_to_task (slug ,
700+ task ,
701+ task = get_task_or_404 (slug , task ['identifier' ]))
702+ db .session .add (t )
624703
625704 # commit all dirty tasks at once.
626705 db .session .commit ()
0 commit comments