-module(erlcloud_mturk). %% Library initialization. -export([configure/2, configure/3, new/2, new/3]). -export([decode_xml/1]). %% Mechanical Turk API Functions -export([ approve_assignment/2, approve_assignment/3, assign_qualification/2, assign_qualification/3, assign_qualification/4, assign_qualification/5, block_worker/2, block_worker/3, change_hit_type_of_hit/2, change_hit_type_of_hit/3, create_hit/5, create_hit/6, create_hit/1, create_hit/2, create_qualification_type/1, create_qualification_type/2, disable_hit/1, disable_hit/2, dispose_hit/1, dispose_hit/2, dispose_qualification_type/1, dispose_qualification_type/2, extend_hit/3, extend_hit/4, force_expire_hit/1, force_expire_hit/2, get_account_balance/0, get_account_balance/1, get_assignments_for_hit/1, get_assignments_for_hit/2, get_assignments_for_hit/3, get_bonus_payments_for_hit/2, get_bonus_payments_for_hit/3, get_bonus_payments_for_assignment/2, get_bonus_payments_for_assignment/3, get_file_upload_url/2, get_file_upload_url/3, get_hit/1, get_hit/2, get_hits_for_qualification_type/1, get_hits_for_qualification_type/2, get_hits_for_qualification_type/3, get_qualification_requests/0, get_qualification_requests/1, get_qualification_requests/2, get_qualification_score/2, get_qualification_score/3, get_qualification_type/1, get_qualification_type/2, get_qualifications_for_qualification_type/1, get_qualifications_for_qualification_type/2, get_qualifications_for_qualification_type/3, get_requester_statistic/2, get_requester_statistic/3, get_requester_statistic/4, get_reviewable_hits/0, get_reviewable_hits/1, get_reviewable_hits/2, grant_bonus/4, grant_bonus/5, grant_qualification/1, grant_qualification/2, grant_qualification/3, notify_workers/3, notify_workers/4, register_hit_type/1, register_hit_type/2, reject_assignment/1, reject_assignment/2, reject_assignment/3, reject_qualification_request/1, reject_qualification_request/2, reject_qualification_request/3, revoke_qualification/2, revoke_qualification/3, revoke_qualification/4, search_hits/0, search_hits/1, search_hits/2, search_qualification_types/0, search_qualification_types/1, search_qualification_types/2, send_test_event_notification/2, send_test_event_notification/3, set_hit_as_reviewing/1, set_hit_as_reviewing/2, set_hit_as_reviewing/3, set_hit_type_notification/2, set_hit_type_notification/3, set_hit_type_notification/4, unblock_worker/1, unblock_worker/2, update_qualification_score/3, update_qualification_score/4, update_qualification_type/1, update_qualification_type/2 ]). -include("erlcloud.hrl"). -include("erlcloud_aws.hrl"). -include("erlcloud_mturk.hrl"). -include_lib("xmerl/include/xmerl.hrl"). -define(API_VERSION, "2008-08-02"). -define(API_SERVICE, "AWSMechanicalTurkRequester"). -define(DEFAULT_NOTIFICATION_VERSION, "2006-05-05"). -define(XMLNS_QUESTIONFORM, "http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionForm.xsd"). -define(XMLNS_EXTERNALQUESTION, "http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2006-07-14/ExternalQuestion.xsd"). -define(XMLNS_ANSWERKEY, "http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/AnswerKey.xsd"). -spec new(string(), string()) -> aws_config(). new(AccessKeyId, SecretAccessKey) -> #aws_config{access_key_id=AccessKeyId, secret_access_key=SecretAccessKey}. -spec new(string(), string(), string()) -> aws_config(). new(AccessKeyId, SecretAccessKey, Host) -> #aws_config{access_key_id=AccessKeyId, secret_access_key=SecretAccessKey, mturk_host=Host}. -spec configure(string(), string()) -> ok. configure(AccessKeyId, SecretAccessKey) -> put(aws_config, new(AccessKeyId, SecretAccessKey)), ok. -spec configure(string(), string(), string()) -> ok. configure(AccessKeyId, SecretAccessKey, Host) -> put(aws_config, new(AccessKeyId, SecretAccessKey, Host)), ok. default_config() -> erlcloud_aws:default_config(). -spec approve_assignment(string(), string() | none) -> ok | no_return(). approve_assignment(AssignmentId, RequesterFeedback) -> approve_assignment(AssignmentId, RequesterFeedback, default_config()). -spec approve_assignment(string(), string() | none, aws_config()) -> ok | no_return(). approve_assignment(AssignmentId, RequesterFeedback, Config) when is_list(AssignmentId), is_list(RequesterFeedback) orelse RequesterFeedback =:= none -> mturk_simple_request(Config, "ApproveAssignment", [{"AssignmentId", AssignmentId}, {"RequesterFeedback", RequesterFeedback}]). -spec assign_qualification(string(), string()) -> ok | no_return(). assign_qualification(QualificationTypeId, WorkerId) -> assign_qualification(QualificationTypeId, WorkerId, default_config()). -spec assign_qualification(string(), string(), integer() | aws_config()) -> ok | no_return(). assign_qualification(QualificationTypeId, WorkerId, Config) when is_record(Config, aws_config) -> assign_qualification(QualificationTypeId, WorkerId, 1, Config); assign_qualification(QualificationTypeId, WorkerId, IntegerValue) -> assign_qualification(QualificationTypeId, WorkerId, IntegerValue, false). -spec assign_qualification(string(), string(), integer(), boolean() | aws_config()) -> ok | no_return(). assign_qualification(QualificationTypeId, WorkerId, IntegerValue, Config) when is_record(Config, aws_config) -> assign_qualification(QualificationTypeId, WorkerId, IntegerValue, false, Config); assign_qualification(QualificationTypeId, WorkerId, IntegerValue, SendNotification) -> assign_qualification(QualificationTypeId, WorkerId, IntegerValue, SendNotification, default_config()). -spec assign_qualification(string(), string(), integer(), boolean(), aws_config()) -> ok | no_return(). assign_qualification(QualificationTypeId, WorkerId, IntegerValue, SendNotification, Config) when is_list(QualificationTypeId), is_list(WorkerId), is_integer(IntegerValue), is_boolean(SendNotification) -> mturk_simple_request(Config, "AssignQualification", [{"QualificationTypeId", QualificationTypeId}, {"WorkerId", WorkerId}, {"IntegerValue", IntegerValue}, {"SendNotification", SendNotification}]). -spec block_worker(string(), string()) -> ok | no_return(). block_worker(WorkerId, Reason) -> block_worker(WorkerId, Reason, default_config()). -spec block_worker(string(), string(), aws_config()) -> ok | no_return(). block_worker(WorkerId, Reason, Config) when is_list(WorkerId), is_list(Reason) -> mturk_simple_request(Config, "BlockWorker", [{"WorkerId", WorkerId}, {"Reason", Reason}]). -spec change_hit_type_of_hit(string(), string()) -> ok | no_return(). change_hit_type_of_hit(HITId, HITTypeId) -> change_hit_type_of_hit(HITId, HITTypeId, default_config()). -spec change_hit_type_of_hit(string(), string(), aws_config()) -> ok | no_return(). change_hit_type_of_hit(HITId, HITTypeId, Config) when is_list(HITId), is_list(HITTypeId) -> mturk_simple_request(Config, "ChangeHITTypeOfHIT", [{"HITId", HITId}, {"HITTypeId", HITTypeId}]). -spec create_hit(string(), mturk_question(), 30..3153600, 1..1000000000, string() | none) -> proplist() | no_return(). create_hit(HITTypeId, Question, LifetimeInSeconds, MaxAssignments, RequesterAnnotation) -> create_hit(HITTypeId, Question, LifetimeInSeconds, MaxAssignments, RequesterAnnotation, default_config()). -spec create_hit(string(), mturk_question(), 30..3153600, 1..1000000000, string() | none, aws_config()) -> proplist() | no_return(). create_hit(HITTypeId, Question, LifetimeInSeconds, MaxAssignments, RequesterAnnotation, Config) when is_list(HITTypeId), is_integer(LifetimeInSeconds), LifetimeInSeconds >= 30, LifetimeInSeconds =< 31536000, is_integer(MaxAssignments), MaxAssignments >= 1, MaxAssignments =< 1000000000, is_list(RequesterAnnotation) orelse RequesterAnnotation =:= none -> QuestionXML = xml_to_string(encode_xml(Question)), Params = [ {"HITTypeId", HITTypeId}, {"Question", QuestionXML}, {"LifetimeInSeconds", LifetimeInSeconds}, {"MaxAssignments", MaxAssignments}, {"RequesterAnnotation", RequesterAnnotation} ], Doc = mturk_xml_request(Config, "CreateHIT", Params), erlcloud_xml:decode( [ {hit_id, "HITId", text}, {hit_type_id, "HITTypeId", text} ], Doc ). -spec create_hit(#mturk_hit{}) -> proplist() | no_return(). create_hit(HIT) -> create_hit(HIT, default_config()). -spec create_hit(#mturk_hit{}, aws_config()) -> proplist() | no_return(). create_hit(HIT, Config) -> QuestionXML = xml_to_string(encode_xml(HIT#mturk_hit.question)), Params = [ {"Title", HIT#mturk_hit.title}, {"Description", HIT#mturk_hit.description}, {"AssignmentDurationInSeconds", HIT#mturk_hit.assignment_duration_in_seconds}, {"LifetimeInSeconds", HIT#mturk_hit.lifetime_in_seconds}, {"Keywords", string:join(HIT#mturk_hit.keywords, ",")}, {"MaxAssignments", HIT#mturk_hit.max_assignments}, {"AutoApprovalDelayInSeconds", HIT#mturk_hit.auto_approval_delay_in_seconds}, {"RequesterAnnotation", HIT#mturk_hit.requester_annotation}, {"Question", QuestionXML}] ++ erlcloud_aws:param_list([encode_money(HIT#mturk_hit.reward)], "Reward") ++ erlcloud_aws:param_list([encode_qualification_requirement(QR) || QR <- HIT#mturk_hit.qualification_requirements], "QualificationRequirement"), Doc = mturk_xml_request(Config, "CreateHIT", Params), erlcloud_xml:decode( [ {hit_id, "HITId", text}, {hit_type_id, "HITTypeId", text} ], Doc ). encode_qualification_requirement(QR) -> [ {"QualificationTypeId", QR#mturk_qualification_requirement.qualification_type_id}, {"Comparator", encode_comparator(QR#mturk_qualification_requirement.comparator)}, {"IntegerValue", QR#mturk_qualification_requirement.integer_value}, {"LocaleValue", encode_locale_value(QR#mturk_qualification_requirement.locale_value)}, {"RequiredToPreview", QR#mturk_qualification_requirement.required_to_preview} ]. encode_comparator('<') -> "LessThan"; encode_comparator('=<') -> "LessThanOrEqualTo"; encode_comparator('>') -> "GreaterThan"; encode_comparator('>=') -> "GreaterThanOrEqualTo"; encode_comparator('==') -> "EqualTo"; encode_comparator('/=') -> "NotEqualTo"; encode_comparator(exists) -> "Exists". decode_comparator("LessThan") -> '<'; decode_comparator("LessThanOrEqualTo") -> '=<'; decode_comparator("GreaterThan") -> '>'; decode_comparator("GreaterThanOrEqualTo") -> '>='; decode_comparator("EqualTo") -> '=='; decode_comparator("NotEqualTo") -> '/='; decode_comparator("Exists") -> exists. encode_locale_value(undefined) -> []; encode_locale_value(#mturk_locale{country_code=Country}) -> [{"Country", Country}]. -spec create_qualification_type(#mturk_qualification_type{}) -> proplist() | no_return(). create_qualification_type(QType) -> create_qualification_type(QType, default_config()). -spec create_qualification_type(#mturk_qualification_type{}, aws_config()) -> proplist() | no_return(). create_qualification_type(QType, Config) when is_record(QType, mturk_qualification_type) -> Doc = mturk_xml_request(Config, "CreateQualificationType", qualification_type_params(QType)), hd(extract_qualification_types([Doc])). qualification_type_params(QType) -> #mturk_qualification_type{name=Name, description=Description, keywords=Keywords, retry_delay_in_seconds=RTD, qualification_type_status=InitialStatus, test=Test, answer_key=AnswerKey, test_duration_in_seconds=TD, auto_granted=AutoGranted, auto_granted_value=AutoGrantedValue} = QType, [ {"Name", Name}, {"Description", Description}, {"Keywords", string:join(Keywords, ",")}, {"RetryDelayInSeconds", RTD}, {"QualificationTypeStatus", encode_qualification_type_status(InitialStatus)}, {"Test", xml_to_string(encode_xml(Test))}, {"AnswerKey", xml_to_string(encode_xml(AnswerKey))}, {"TestDurationInSeconds", TD}, {"AutoGranted", AutoGranted}, {"AutoGrantedValue", case AutoGranted of true -> AutoGrantedValue; false -> undefined end} ]. -spec disable_hit(string()) -> ok | no_return(). disable_hit(HITId) -> disable_hit(HITId, default_config()). -spec disable_hit(string(), aws_config()) -> ok | no_return(). disable_hit(HITId, Config) when is_list(HITId) -> mturk_simple_request(Config, "DisableHIT", [{"HITId", HITId}]). -spec dispose_hit(string()) -> ok | no_return(). dispose_hit(HITId) -> dispose_hit(HITId, default_config()). -spec dispose_hit(string(), aws_config()) -> ok | no_return(). dispose_hit(HITId, Config) when is_list(HITId) -> mturk_simple_request(Config, "DisposeHIT", [{"HITId", HITId}]). -spec dispose_qualification_type(string()) -> ok | no_return(). dispose_qualification_type(QualificationTypeId) -> dispose_qualification_type(QualificationTypeId, default_config()). -spec dispose_qualification_type(string(), aws_config()) -> ok | no_return(). dispose_qualification_type(QualificationTypeId, Config) when is_list(QualificationTypeId) -> mturk_simple_request(Config, "DisposeQualificationType", [{"QualificationTypeId", QualificationTypeId}]). -spec extend_hit(string(), 1..1000000000 | none, 3600..31536000 | none) -> ok | no_return(). extend_hit(HITId, MaxAssignmentsIncrement, ExpirationIncrementInSeconds) -> extend_hit(HITId, MaxAssignmentsIncrement, ExpirationIncrementInSeconds, default_config()). -spec extend_hit(string(), 1..1000000000 | none, 3600..31536000 | none, aws_config()) -> ok | no_return(). extend_hit(HITId, MaxAssignmentsIncrement, ExpirationIncrementInSeconds, Config) when is_list(HITId), (MaxAssignmentsIncrement >= 1 andalso MaxAssignmentsIncrement =< 1000000000) orelse MaxAssignmentsIncrement =:= none, (ExpirationIncrementInSeconds >= 3600 andalso ExpirationIncrementInSeconds =< 31536000) orelse ExpirationIncrementInSeconds =:= none, MaxAssignmentsIncrement =/= none orelse ExpirationIncrementInSeconds =/= none -> mturk_simple_request(Config, "ExtendHIT", [{"HITId", HITId}, {"MaxAssignmentsIncrement", MaxAssignmentsIncrement}, {"ExpirationIncrementInSeconds", ExpirationIncrementInSeconds}]). -spec force_expire_hit(string()) -> ok | no_return(). force_expire_hit(HITId) -> force_expire_hit(HITId, default_config()). -spec force_expire_hit(string(), aws_config()) -> ok | no_return(). force_expire_hit(HITId, Config) when is_list(HITId) -> mturk_simple_request(Config, "ForceExpireHIT", [{"HITId", HITId}]). -spec get_account_balance() -> proplist() | no_return(). get_account_balance() -> get_account_balance(default_config()). -spec get_account_balance(aws_config()) -> proplist() | no_return(). get_account_balance(Config) -> Doc = mturk_xml_request(Config, "GetAccountBalance", []), erlcloud_xml:decode( [ {available_balance, "AvailableBalance", {single, fun extract_money/1}}, {on_hold_balance, "OnHoldBalance", {single, fun extract_money/1}} ], Doc ). -spec get_assignments_for_hit(string()) -> proplist() | no_return(). get_assignments_for_hit(HITId) -> get_assignments_for_hit(HITId, []). -spec get_assignments_for_hit(string(), proplist() | aws_config()) -> proplist() | no_return(). get_assignments_for_hit(HITId, Config) when is_record(Config, aws_config) -> get_assignments_for_hit(HITId, [], Config); get_assignments_for_hit(HITId, Options) -> get_assignments_for_hit(HITId, Options, default_config()). -spec get_assignments_for_hit(string(), proplist(), aws_config()) -> proplist() | no_return(). get_assignments_for_hit(HITId, Options, Config) when is_list(HITId), is_list(Options) -> Params = [ {"HITId", HITId}, {"AssignmentStatus", case proplists:get_value(assignment_status, Options) of undefined -> undefined; submitted -> "Submitted"; approved -> "Approved"; rejected -> "Rejected" end }, {"SortProperty", case proplists:get_value(sort_property, Options) of undefined -> undefined; accept_time -> "AcceptTime"; submit_time -> "SubmitTime"; assignment_status -> "AssignmentStatus" end }, {"SortDirection", case proplists:get_value(sort_direction, Options) of undefined -> undefined; ascending -> "Ascending"; descending -> "Descending" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetAssignmentsForHIT", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {assignments, "Assignment", fun extract_assignments/1} ], Doc ). extract_assignments(Assignments) -> [extract_assignment(Assignment) || Assignment <- Assignments]. extract_assignment(Assignment) -> erlcloud_xml:decode( [ {assignment_id, "AssignmentId", text}, {worker_id, "WorkerId", text}, {hit_id, "HITId", text}, {assignment_status, "AssignmentStatus", text}, {auto_approval_time, "AutoApprovalTime", time}, {accept_time, "AcceptTime", time}, {submit_time, "SubmitTime", time}, {approval_time, "ApprovalTime", time}, {answers, "Answer", {single, fun decode_xml/1}} ], Assignment ). -spec get_bonus_payments_for_hit(string(), proplist()) -> proplist() | no_return(). get_bonus_payments_for_hit(HITId, Options) -> get_bonus_payments_for_hit(HITId, Options, default_config()). -spec get_bonus_payments_for_hit(string(), proplist(), aws_config()) -> proplist() | no_return(). get_bonus_payments_for_hit(HITId, Options, Config) when is_list(HITId), is_list(Options) -> Params = [ {"HITId", HITId}, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetBonusPayments", Params), extract_bonus_payments(Doc). -spec get_bonus_payments_for_assignment(string(), proplist()) -> proplist() | no_return(). get_bonus_payments_for_assignment(AssignmentId, Options) -> get_bonus_payments_for_assignment(AssignmentId, Options, default_config()). -spec get_bonus_payments_for_assignment(string(), proplist(), aws_config()) -> proplist() | no_return(). get_bonus_payments_for_assignment(AssignmentId, Options, Config) when is_list(AssignmentId), is_list(Options) -> Params = [ {"AssignmentId", AssignmentId}, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetBonusPayments", Params), extract_bonus_payments(Doc). extract_bonus_payments(Payments) when is_list(Payments) -> [extract_bonus_payment(Payment) || Payment <- Payments]; extract_bonus_payments(Doc) -> erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {bonus_payments, "BonusPayment", fun extract_bonus_payments/1} ], Doc ). extract_bonus_payment(Payment) -> erlcloud_xml:decode( [ {worker_id, "WorkerId", text}, {bonus_amount, "BonusAmount", {single, fun extract_money/1}}, {assignment_id, "AssignmentId", text}, {reason, "Reason", text}, {grant_time, "GrantTime", time} ], Payment ). -spec get_file_upload_url(string(), string()) -> string() | no_return(). get_file_upload_url(AssignmentId, QuestionIdentifier) -> get_file_upload_url(AssignmentId, QuestionIdentifier, default_config()). -spec get_file_upload_url(string(), string(), aws_config()) -> string() | no_return(). get_file_upload_url(AssignmentId, QuestionIdentifier, Config) when is_record(Config, aws_config) -> Params = [ {"AssignmentId", AssignmentId}, {"QuestionIdentifier", QuestionIdentifier} ], Doc = mturk_xml_request(Config, "GetFileUploadURL", Params), erlcloud_xml:get_text("FileUploadURL", Doc). -spec get_hit(string()) -> #mturk_hit{} | no_return(). get_hit(HITId) -> get_hit(HITId, default_config()). -spec get_hit(string(), aws_config()) -> #mturk_hit{} | no_return(). get_hit(HITId, Config) when is_list(HITId) -> Doc = mturk_xml_request(Config, "GetHIT", [{"HITId", HITId}]), hd(extract_hits([Doc])). -spec get_hits_for_qualification_type(string()) -> proplist() | no_return(). get_hits_for_qualification_type(QualificationTypeId) -> get_hits_for_qualification_type(QualificationTypeId, []). -spec get_hits_for_qualification_type(string(), proplist() | aws_config()) -> proplist() | no_return(). get_hits_for_qualification_type(QualificationTypeId, Config) when is_record(Config, aws_config) -> get_hits_for_qualification_type(QualificationTypeId, [], Config); get_hits_for_qualification_type(QualificationTypeId, Options) -> get_hits_for_qualification_type(QualificationTypeId, Options, default_config()). -spec get_hits_for_qualification_type(string(), proplist(), aws_config()) -> proplist() | no_return(). get_hits_for_qualification_type(QualificationTypeId, Options, Config) when is_list(Options) -> Params = [ {"QualificationTypeId", QualificationTypeId}, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetHITsForQualificationType", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {hits, "HIT", fun extract_hits/1} ], Doc ). -spec get_reviewable_hits() -> proplist() | no_return(). get_reviewable_hits() -> get_reviewable_hits([]). -spec get_reviewable_hits(proplist() | aws_config()) -> proplist() | no_return(). get_reviewable_hits(Config) when is_record(Config, aws_config) -> get_reviewable_hits([], Config); get_reviewable_hits(Options) -> get_reviewable_hits(Options, default_config()). -spec get_reviewable_hits(proplist(), aws_config()) -> proplist() | no_return(). get_reviewable_hits(Options, Config) when is_list(Options) -> Params = [ {"HITTypeId", proplists:get_value(hit_type_id, Options)}, {"Status", case proplists:get_value(status, Options) of undefined -> undefined; reviewable -> "Reviewable"; reviewing -> "Reviewing" end }, {"SortProperty", case proplists:get_value(sort_property, Options) of undefined -> undefined; title -> "Title"; reward -> "Reward"; expiration -> "Expiration"; creation_time -> "CreationTime"; enumeration -> "Enumeration" end }, {"SortDirection", case proplists:get_value(sort_direction, Options) of undefined -> undefined; ascending -> "Ascending"; descending -> "Descending" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetReviewableHITs", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {hit_ids, "HIT/HITId", list} ], Doc ). -spec get_qualification_score(string(), string()) -> proplist() | no_return(). get_qualification_score(QualificationTypeId, SubjectId) -> get_qualification_score(QualificationTypeId, SubjectId, default_config()). -spec get_qualification_score(string(), string(), aws_config()) -> proplist() | no_return(). get_qualification_score(QualificationTypeId, SubjectId, Config) when is_list(QualificationTypeId), is_list(SubjectId) -> Doc = mturk_xml_request(Config, "GetQualificationScore", [ {"QualificationTypeId", QualificationTypeId}, {"SubjectId", SubjectId} ] ), erlcloud_xml:decode( [ {qualification_type_id, "QualificationTypeId", text}, {subject_id, "SubjectId", optional_text}, {grant_time, "GrantTime", time}, {integer_value, "IntegerValue", integer} ], Doc ). -spec get_qualification_type(string()) -> #mturk_qualification_type{} | no_return(). get_qualification_type(QualificationTypeId) -> get_qualification_type(QualificationTypeId, default_config()). -spec get_qualification_type(string(), aws_config()) -> #mturk_qualification_type{} | no_return(). get_qualification_type(QualificationTypeId, Config) when is_record(Config, aws_config) -> Doc = mturk_xml_request(Config, "GetQualificationType", [{"QualificationTypeId", QualificationTypeId}]), extract_qualification_type(Doc). extract_qualification_types(Nodes) -> [extract_qualification_type(Node) || Node <- Nodes]. extract_qualification_type(Node) -> erlcloud_xml:decode( [ {#mturk_qualification_type.qualification_type_id, "QualificationTypeId", text}, {#mturk_qualification_type.creation_time, "CreationTime", time}, {#mturk_qualification_type.name, "Name", text}, {#mturk_qualification_type.description, "Description", text}, {#mturk_qualification_type.keywords, "Keywords", {value, fun decode_keywords/1}}, {#mturk_qualification_type.qualification_type_status, "QualificationTypeStatus", {value, fun decode_qualification_type_status/1}}, {#mturk_qualification_type.retry_delay_in_seconds, "RetryDelayInSeconds", integer}, {#mturk_qualification_type.is_requestable, "IsRequestable", optional_boolean}, {#mturk_qualification_type.test, "Test", {single, fun decode_xml/1}}, {#mturk_qualification_type.answer_key, "AnswerKey", {single, fun decode_xml/1}}, {#mturk_qualification_type.test_duration_in_seconds, "TestDurationInSeconds", integer} ], Node, #mturk_qualification_type{} ). decode_keywords(String) -> [string:strip(Keyword) || Keyword <- string:tokens(String, ",")]. -spec get_qualifications_for_qualification_type(string()) -> [proplist()] | no_return(). get_qualifications_for_qualification_type(QualificationTypeId) -> get_qualifications_for_qualification_type(QualificationTypeId, default_config()). -spec get_qualifications_for_qualification_type(string(), proplist() | aws_config()) -> [proplist()] | no_return(). get_qualifications_for_qualification_type(QualificationTypeId, Config) when is_record(Config, aws_config) -> get_qualifications_for_qualification_type(QualificationTypeId, [], Config); get_qualifications_for_qualification_type(QualificationTypeId, Options) -> get_qualifications_for_qualification_type(QualificationTypeId, Options, default_config()). -spec get_qualifications_for_qualification_type(string(), proplist(), aws_config()) -> [proplist()] | no_return(). get_qualifications_for_qualification_type(QualificationTypeId, Options, Config) when is_list(QualificationTypeId), is_list(Options) -> Params = [ {"QualificationTypeId", QualificationTypeId}, {"Status", case proplists:get_value(status, Options) of undefined -> undefined; granted -> "Granted"; revoked -> "Revoked" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetQualificationsForQualificationType", Params), [erlcloud_xml:decode( [ {qualification_type_id, "QualificationTypeId", text}, {subject_id, "SubjectId", optional_text}, {grant_time, "GrantTime", time}, {integer_value, "IntegerValue", integer} ], Item ) || Item <- xmerl_xpath:string("Qualification", Doc)]. -spec get_qualification_requests() -> proplist() | no_return(). get_qualification_requests() -> get_qualification_requests([]). -spec get_qualification_requests(proplist() | aws_config()) -> proplist() | no_return(). get_qualification_requests(Config) when is_record(Config, aws_config) -> get_qualification_requests([], Config); get_qualification_requests(Options) -> get_qualification_requests(Options, default_config()). -spec get_qualification_requests(proplist(), aws_config()) -> proplist() | no_return(). get_qualification_requests(Options, Config) when is_list(Options) -> Params = [ {"QualificationTypeId", proplists:get_value(qualification_type_id, Options)}, {"SortProperty", case proplists:get_value(sort_property, Options) of undefined -> undefined; qualification_type_id -> "QualificationTypeId"; submit_time -> "SubmitTime" end }, {"SortDirection", case proplists:get_value(sort_direction, Options) of undefined -> undefined; ascending -> "Ascending"; descending -> "Descending" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "GetQualificationRequests", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {qualification_requests, "QualificationRequest", fun extract_qualification_requests/1} ], Doc ). extract_qualification_requests(Requests) -> [extract_qualification_request(Request) || Request <- Requests]. extract_qualification_request(Request) -> erlcloud_xml:decode( [ {qualification_request_id, "QualificationRequestId", text}, {qualification_type_id, "QualificationTypeId", text}, {subject_id, "SubjectId", text}, {test, "Test", {single, fun decode_xml/1}}, {answer, "Answer", {single, fun decode_xml/1}}, {submit_time, "SubmitTime", time} ], Request ). -spec get_requester_statistic(string(), one_day | seven_days | thirty_days | life_to_date) -> [{datetime(), float()}] | no_return(). get_requester_statistic(Statistic, TimePeriod) -> get_requester_statistic(Statistic, TimePeriod, default_config()). -spec get_requester_statistic(string(), one_day | seven_days | thirty_days | life_to_date, pos_integer() | aws_config()) -> [{datetime(), float()}] | no_return(). get_requester_statistic(Statistic, TimePeriod, Config) when is_record(Config, aws_config) -> get_requester_statistic(Statistic, TimePeriod, 1, Config); get_requester_statistic(Statistic, TimePeriod, Count) -> get_requester_statistic(Statistic, TimePeriod, Count, default_config()). -spec get_requester_statistic(string(), one_day | seven_days | thirty_days | life_to_date, pos_integer(), aws_config()) -> [{datetime(), float()}] | no_return(). get_requester_statistic(Statistic, TimePeriod, Count, Config) when is_list(Statistic), TimePeriod =:= one_day orelse TimePeriod =:= seven_days orelse TimePeriod =:= thirty_days orelse TimePeriod =:= life_to_date, is_integer(Count), Count >= 1 -> Doc = mturk_xml_request(Config, "GetRequesterStatistic", [ {"Statistic", Statistic}, {"TimePeriod", case TimePeriod of one_day -> "OneDay"; seven_days -> "SevenDays"; thirty_days -> "ThirtyDays"; life_to_date -> "LifeToDate" end } ] ), [{erlcloud_xml:get_time("Date", DP), case erlcloud_xml:get_text("DoubleValue", DP) of [] -> erlcloud_xml:get_integer("LongValue", DP); DVal -> try list_to_float(DVal) catch error:badarg -> list_to_integer(DVal) + 0.0 end end} || DP <- xmerl_xpath:string("DataPoint", Doc)]. -spec grant_bonus(string(), string(), #mturk_money{}, string()) -> ok | no_return(). grant_bonus(WorkerId, AssignmentId, BonusAmount, Reason) -> grant_bonus(WorkerId, AssignmentId, BonusAmount, Reason, default_config()). -spec grant_bonus(string(), string(), #mturk_money{}, string(), aws_config()) -> ok | no_return(). grant_bonus(WorkerId, AssignmentId, BonusAmount, Reason, Config) -> mturk_simple_request(Config, "GrantBonus", [ {"WorkerId", WorkerId}, {"AssignmentId", AssignmentId}, {"Reason", Reason}| erlcloud_aws:param_list([encode_money(BonusAmount)], "BonusAmount") ] ). -spec grant_qualification(string()) -> ok | no_return(). grant_qualification(QualificationRequestId) -> grant_qualification(QualificationRequestId, none). -spec grant_qualification(string(), integer() | none | aws_config()) -> ok | no_return(). grant_qualification(QualificationRequestId, Config) when is_record(Config, aws_config) -> grant_qualification(QualificationRequestId, none, Config); grant_qualification(QualificationRequestId, Value) -> grant_qualification(QualificationRequestId, Value, default_config()). -spec grant_qualification(string(), integer() | none, aws_config()) -> ok | no_return(). grant_qualification(QualificationRequestId, Value, Config) when is_list(QualificationRequestId), is_integer(Value) orelse Value =:= none -> mturk_simple_request(Config, "GrantQualification", [ {"QualificationRequestId", QualificationRequestId}, {"IntegerValue", Value} ] ). extract_hits(HITs) -> [extract_hit(HIT) || HIT <- HITs]. extract_hit(HIT) -> erlcloud_xml:decode( [ {#mturk_hit.hit_id, "HITId", text}, {#mturk_hit.hit_type_id, "HITTypeId", text}, {#mturk_hit.creation_time, "CreationTime", time}, {#mturk_hit.title, "Title", text}, {#mturk_hit.description, "Description", text}, {#mturk_hit.keywords, "Keywords", {value, fun decode_keywords/1}}, {#mturk_hit.requester_annotation, "RequesterAnnotation", text}, {#mturk_hit.qualification_requirements, "QualificationRequirement", fun extract_qualification_requirements/1}, {#mturk_hit.question, "Question", {single, fun decode_xml/1}}, {#mturk_hit.hit_status, "HITStatus", text}, {#mturk_hit.max_assignments, "MaxAssignments", integer}, {#mturk_hit.reward, "Reward", {single, fun extract_money/1}}, {#mturk_hit.auto_approval_delay_in_seconds, "AutoApprovalDelayInSeconds", integer}, {#mturk_hit.expiration, "Expiration", time}, {#mturk_hit.assignment_duration_in_seconds, "AssignmentDurationInSeconds", integer}, {#mturk_hit.number_of_assignments_pending, "NumberOfAssignmentsPending", optional_integer}, {#mturk_hit.number_of_assignments_available, "NumberOfAssignmentsAvailable", optional_integer}, {#mturk_hit.number_of_assignments_completed, "NumberOfAssignmentsCompleted", optional_integer}, {#mturk_hit.number_of_similar_hits, "NumberOfSimilarHITs", optional_integer}, {#mturk_hit.hit_review_status, "HITReviewStatus", optional_text} ], HIT, #mturk_hit{} ). decode_xml(List) when is_list(List) -> [decode_xml(Element) || Element <- List, is_record(Element, xmlElement)]; decode_xml(#xmlElement{name='Answer', parents=[{'QuestionFormAnswers', _}|_]} = Element) -> erlcloud_xml:decode( [ {#mturk_answer.question_identifier, "QuestionIdentifier", text}, {#mturk_answer.free_text, "FreeText", optional_text}, {#mturk_answer.selection_identifier, "SelectionIdentifier", optional_text}, {#mturk_answer.uploaded_file_size_in_bytes, "UploadedFileSizeInBytes", optional_integer}, {#mturk_answer.uploaded_file_key, "UploadedFileKey", optional_text} ], Element, #mturk_answer{} ); decode_xml(#xmlElement{name='Answer'} = Element) -> AnswerXML = element(1,xmerl_scan:string(erlcloud_xml:get_text(Element))), decode_xml(AnswerXML); decode_xml(#xmlElement{name='QuestionFormAnswers', content=Content}) -> decode_xml(Content); decode_xml(#xmlElement{name='AnswerKey', parents=[]} = Element) -> erlcloud_xml:decode( [ {#mturk_answer_key.answers, "Question", fun decode_xml/1}, {#mturk_answer_key.qualification_value_mapping, "QualificationValueMapping", {single, fun decode_xml/1}} ], Element, #mturk_answer_key{} ); decode_xml(#xmlElement{name='QualificationValueMapping', content=Content}) -> hd(decode_xml(Content)); decode_xml(#xmlElement{name='PercentageMapping'} = Element) -> erlcloud_xml:decode( [ {#mturk_percentage_mapping.maximum_summed_score, "MaximumSummedScore", integer} ], Element, #mturk_percentage_mapping{} ); decode_xml(#xmlElement{name='ScaleMapping'} = Element) -> erlcloud_xml:decode( [ {#mturk_scale_mapping.summed_score_multiplier, "SummedScoreMultiplier", integer} ], Element, #mturk_percentage_mapping{} ); decode_xml(#xmlElement{name='Test'} = Element) -> XML = element(1,xmerl_scan:string(erlcloud_xml:get_text(Element))), decode_xml(XML); decode_xml(#xmlElement{name='AnswerKey'} = Element) -> XML = element(1,xmerl_scan:string(erlcloud_xml:get_text(Element))), decode_xml(XML); decode_xml(#xmlElement{name='AnswerOption'} = Element) -> erlcloud_xml:decode( [ {#mturk_answer_option.selection_identifier, "SelectionIdentifier", text}, {#mturk_answer_option.answer_score, "AnswerScore", integer} ], Element, #mturk_answer_option{} ); decode_xml(#xmlElement{name='Question', parents=[{'AnswerKey', _}|_]} = Element) -> erlcloud_xml:decode( [ {#mturk_test_answer.question_identifier, "QuestionIdentifier", text}, {#mturk_test_answer.answer_options, "AnswerOption", fun decode_xml/1}, {#mturk_test_answer.default_score, "DefaultScore", optional_integer} ], Element, #mturk_test_answer{} ); decode_xml(#xmlElement{name='ExternalQuestion'} = Element) -> erlcloud_xml:decode( [ {#mturk_external_question.external_url, "ExternalURL", text}, {#mturk_external_question.frame_height, "FrameHeight", integer} ], Element, #mturk_external_question{} ); decode_xml(#xmlElement{name='QuestionForm', content=Content}) -> #mturk_question_form{content=decode_xml(Content)}; decode_xml(#xmlElement{name='Question', parents=[{'QuestionForm', _}|_]} = Element) -> erlcloud_xml:decode( [ {#mturk_question.question_identifier, "QuestionIdentifier", text}, {#mturk_question.display_name, "DisplayName", text}, {#mturk_question.is_required, "IsRequired", boolean}, {#mturk_question.question_content, "QuestionContent", {single, fun decode_xml/1}}, {#mturk_question.answer_specification, "AnswerSpecification", {single, fun decode_xml/1}} ], Element, #mturk_question{} ); decode_xml(#xmlElement{name='Question'} = Element) -> XML = element(1,xmerl_scan:string(erlcloud_xml:get_text(Element))), decode_xml(XML); decode_xml(#xmlElement{name='QuestionContent', content=Content}) -> decode_xml(Content); decode_xml(#xmlElement{name='AnswerSpecification', content=Content}) -> hd(decode_xml(Content)); decode_xml(#xmlElement{name='FreeTextAnswer'} = Element) -> erlcloud_xml:decode( [ {#mturk_free_text_answer.constraints, "Constraints", {single, fun decode_xml/1}}, {#mturk_free_text_answer.default_text, "DefaultText", text}, {#mturk_free_text_answer.number_of_lines_suggestion, "NumberOfLinesSuggestion", integer} ], Element, #mturk_free_text_answer{} ); decode_xml(#xmlElement{name='Constraints'} = Element) -> erlcloud_xml:decode( [ {#mturk_constraints.is_numeric, "IsNumeric", present}, {#mturk_constraints.min_value, {"IsNumeric", "minValue"}, optional_integer}, {#mturk_constraints.max_value, {"IsNumeric", "maxValue"}, optional_integer}, {#mturk_constraints.min_length, {"Length", "minLength"}, optional_integer}, {#mturk_constraints.max_length, {"Length", "maxLength"}, optional_integer}, {#mturk_constraints.answer_format_regex, {"AnswerFormatRegex", "regex"}, optional_text}, {#mturk_constraints.answer_format_regex_error_text, {"AnswerFormatRegex", "errorText"}, optional_text}, {#mturk_constraints.answer_format_regex_flags, {"AnswerFormatRegex", "flags"}, optional_text} ], Element, #mturk_constraints{} ); decode_xml(#xmlElement{name='SelectionAnswer'} = Element) -> erlcloud_xml:decode( [ {#mturk_selection_answer.min_selection_count, "MinSelectionCount", integer}, {#mturk_selection_answer.max_selection_count, "MaxSelectionCount", integer}, {#mturk_selection_answer.style_suggestion, "StyleSuggestion", {value, fun (V) -> list_to_existing_atom(V) end}}, {#mturk_selection_answer.selections, "Selections", {single, fun decode_xml/1}} ], Element, #mturk_selection_answer{} ); decode_xml(#xmlElement{name='Selections', content=Content}) -> decode_xml(Content); decode_xml(#xmlElement{name='Selection'} = Element) -> erlcloud_xml:decode( [ {#mturk_selection.selection_identifier, "SelectionIdentifier", text}, {#mturk_selection.text, "Text", optional_text}, {#mturk_selection.formatted_content, "FormattedContent", optional_text}, {#mturk_selection.binary, "Binary", {single, fun decode_xml/1}} ], Element, #mturk_selection{} ); decode_xml(#xmlElement{name='Overview', content=Content}) -> #mturk_overview{content=decode_xml(Content)}; decode_xml(#xmlElement{name='Text'} = Element) -> {text, erlcloud_xml:get_text(Element)}; decode_xml(#xmlElement{name='Title'} = Element) -> {title, erlcloud_xml:get_text(Element)}; decode_xml(#xmlElement{name='Binary'} = Element) -> erlcloud_xml:decode( [ {#mturk_binary.mime_type, "MimeType", {single, fun decode_xml/1}}, {#mturk_binary.data_url, "DataURL", text}, {#mturk_binary.alt_text, "AltText", text} ], Element, #mturk_binary{} ); decode_xml(#xmlElement{name=MimeType} = Element) when MimeType =:= 'MimeType'; MimeType =:= 'EmbeddedMimeType' -> erlcloud_xml:decode( [ {#mturk_mime_type.type, "Type", text}, {#mturk_mime_type.sub_type, "SubType", text} ], Element, #mturk_mime_type{} ); decode_xml(#xmlElement{name='FlashMovie'} = Element) -> erlcloud_xml:decode( [ {#mturk_flash.flash_movie_url, "FlashMovieURL", text}, {#mturk_flash.width, "Width", integer}, {#mturk_flash.height, "Height", integer}, {#mturk_flash.application_parameters, "ApplicationParameter", fun decode_xml/1} ], Element, #mturk_flash{} ); decode_xml(#xmlElement{name='JavaApplet'} = Element) -> erlcloud_xml:decode( [ {#mturk_java_applet.applet_path, "AppletPath", text}, {#mturk_java_applet.applet_filename, "AppletFilename", text}, {#mturk_java_applet.width, "Width", integer}, {#mturk_java_applet.height, "Height", integer}, {#mturk_java_applet.application_parameters, "ApplicationParameter", fun decode_xml/1} ], Element, #mturk_java_applet{} ); decode_xml(#xmlElement{name='EmbeddedBinary'} = Element) -> erlcloud_xml:decode( [ {#mturk_embedded_binary.embedded_mime_type, "MimeType", {single, fun decode_xml/1}}, {#mturk_embedded_binary.data_url, "DataURL", text}, {#mturk_embedded_binary.alt_text, "AltText", text}, {#mturk_embedded_binary.width, "Width", integer}, {#mturk_embedded_binary.height, "Height", integer}, {#mturk_embedded_binary.application_parameters, "ApplicationParameter", fun decode_xml/1} ], Element, #mturk_embedded_binary{} ); decode_xml(#xmlElement{name='ApplicationParameter'} = Element) -> {erlcloud_xml:get_text("Name", Element), erlcloud_xml:get_text("Value", Element)}; decode_xml(#xmlElement{name='FormattedContent'} = Element) -> {formatted_content, erlcloud_xml:get_text(Element)}. extract_qualification_requirements(Reqts) -> [extract_qualification_requirement(Reqt) || Reqt <- Reqts]. extract_qualification_requirement(Reqt) -> erlcloud_xml:decode( [ {#mturk_qualification_requirement.qualification_type_id, "QualificationTypeId", text}, {#mturk_qualification_requirement.comparator, "Comparator", {value, fun decode_comparator/1}}, {#mturk_qualification_requirement.integer_value, "IntegerValue", integer}, {#mturk_qualification_requirement.locale_value, "LocaleValue", {single, fun extract_locale_value/1}}, {#mturk_qualification_requirement.required_to_preview, "RequiredToPreview", boolean} ], Reqt, #mturk_qualification_requirement{} ). extract_locale_value([Item]) -> [#mturk_locale{country_code=erlcloud_xml:get_text("Country", Item)}]. extract_money(Money) -> erlcloud_xml:decode( [ {#mturk_money.amount, "Amount", text}, {#mturk_money.currency_code, "CurrencyCode", text}, {#mturk_money.formatted_price, "FormattedPrice", text} ], Money, #mturk_money{} ). encode_money(#mturk_money{amount=Amount, currency_code=CurrencyCode}) -> [{"Amount", Amount}, {"CurrencyCode", CurrencyCode}]. -spec notify_workers(string(), string(), [string()]) -> ok | no_return(). notify_workers(Subject, MessageText, WorkerIds) -> notify_workers(Subject, MessageText, WorkerIds, default_config()). -spec notify_workers(string(), string(), [string()], aws_config()) -> ok | no_return(). notify_workers(Subject, MessageText, WorkerIds, Config) when is_list(Subject), is_list(MessageText), is_list(WorkerIds), length(WorkerIds) =< 100 -> mturk_simple_request(Config, "NotifyWorkers", [ {"Subject", Subject}, {"MessageText", MessageText}| erlcloud_aws:param_list(WorkerIds, "WorkerId") ] ). -spec register_hit_type(#mturk_hit{}) -> proplist() | no_return(). register_hit_type(HIT) -> register_hit_type(HIT, default_config()). -spec register_hit_type(#mturk_hit{}, aws_config()) -> proplist() | no_return(). register_hit_type(HIT, Config) -> Params = [ {"Title", HIT#mturk_hit.title}, {"Description", HIT#mturk_hit.description}, {"AssignmentDurationInSeconds", HIT#mturk_hit.assignment_duration_in_seconds}, {"Keywords", string:join(HIT#mturk_hit.keywords, ",")}, {"AutoApprovalDelayInSeconds", HIT#mturk_hit.auto_approval_delay_in_seconds}, {"RequesterAnnotation", HIT#mturk_hit.requester_annotation}] ++ erlcloud_aws:param_list([encode_money(HIT#mturk_hit.reward)], "Reward") ++ erlcloud_aws:param_list([encode_qualification_requirement(QR) || QR <- HIT#mturk_hit.qualification_requirements], "QualificationRequirement"), Doc = mturk_xml_request(Config, "RegisterHITType", Params), erlcloud_xml:decode( [ {hit_type_id, "HITTypeId", text} ], Doc ). -spec reject_assignment(string()) -> ok | no_return(). reject_assignment(AssignmentId) -> reject_assignment(AssignmentId, none). -spec reject_assignment(string(), string() | none | aws_config()) -> ok | no_return(). reject_assignment(AssignmentId, Config) when is_record(Config, aws_config) -> reject_assignment(AssignmentId, none, Config); reject_assignment(AssignmentId, Reason) -> reject_assignment(AssignmentId, Reason, default_config()). -spec reject_assignment(string(), string() | none, aws_config()) -> ok | no_return(). reject_assignment(AssignmentId, Reason, Config) when is_list(AssignmentId), is_list(Reason) orelse Reason =:= none -> mturk_simple_request(Config, "RejectAssignment", [ {"AssignmentId", AssignmentId}, {"Reason", Reason} ] ). -spec reject_qualification_request(string()) -> ok | no_return(). reject_qualification_request(QualificationRequestId) -> reject_qualification_request(QualificationRequestId, none). -spec reject_qualification_request(string(), string() | none | aws_config()) -> ok | no_return(). reject_qualification_request(QualificationRequestId, Config) when is_record(Config, aws_config) -> reject_qualification_request(QualificationRequestId, none, Config); reject_qualification_request(QualificationRequestId, Reason) -> reject_qualification_request(QualificationRequestId, Reason, default_config()). -spec reject_qualification_request(string(), string() | none, aws_config()) -> ok | no_return(). reject_qualification_request(QualificationRequestId, Reason, Config) when is_list(QualificationRequestId), is_list(Reason) orelse Reason =:= none -> mturk_simple_request(Config, "RejectQualificationRequest", [ {"QualificationRequestId", QualificationRequestId}, {"Reason", Reason} ] ). -spec revoke_qualification(string(), string()) -> ok | no_return(). revoke_qualification(QualificationTypeId, WorkerId) -> revoke_qualification(QualificationTypeId, WorkerId, none). -spec revoke_qualification(string(), string(), string() | none | aws_config()) -> ok | no_return(). revoke_qualification(QualificationTypeId, WorkerId, Config) when is_record(Config, aws_config) -> revoke_qualification(QualificationTypeId, WorkerId, none, Config); revoke_qualification(QualificationTypeId, WorkerId, Reason) -> revoke_qualification(QualificationTypeId, WorkerId, Reason, default_config()). -spec revoke_qualification(string(), string(), string() | none, aws_config()) -> ok | no_return(). revoke_qualification(QualificationTypeId, WorkerId, Reason, Config) -> mturk_simple_request(Config, "RevokeQualification", [ {"SubjectId", WorkerId}, {"QualificationTypeId", QualificationTypeId}, {"Reason", Reason} ] ). -spec search_hits() -> proplist() | no_return(). search_hits() -> search_hits([]). -spec search_hits(proplist() | aws_config()) -> proplist() | no_return(). search_hits(Config) when is_record(Config, aws_config) -> search_hits([], Config); search_hits(Options) -> search_hits(Options, default_config()). -spec search_hits(proplist(), aws_config()) -> proplist() | no_return(). search_hits(Options, Config) when is_list(Options) -> Params = [ {"SortProperty", case proplists:get_value(sort_property, Options) of undefined -> undefined; title -> "Title"; reward -> "Reward"; expiration -> "Expiration"; creation_time -> "CreationTime"; enumeration -> "Enumeration" end }, {"SortDirection", case proplists:get_value(sort_direction, Options) of undefined -> undefined; ascending -> "Ascending"; descending -> "Descending" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "SearchHITs", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {hits, "HIT", fun extract_hits/1} ], Doc ). -spec search_qualification_types() -> proplist() | no_return(). search_qualification_types() -> search_qualification_types([]). -spec search_qualification_types(proplist() | aws_config()) -> proplist() | no_return(). search_qualification_types(Config) when is_record(Config, aws_config) -> search_qualification_types([], Config); search_qualification_types(Options) -> search_qualification_types(Options, default_config()). -spec search_qualification_types(proplist(), aws_config()) -> proplist() | no_return(). search_qualification_types(Options, Config) -> Params = [ {"Query", proplists:get_value(search_query, Options)}, {"MustBeRequestable", proplists:get_value(must_be_requestable, Options)}, {"MustBeOwnedByCaller", proplists:get_value(must_be_owned_by_caller, Options)}, {"SortProperty", case proplists:get_value(sort_property, Options) of undefined -> undefined; name -> "Name" end }, {"SortDirection", case proplists:get_value(sort_direction, Options) of undefined -> undefined; ascending -> "Ascending"; descending -> "Descending" end }, {"PageSize", proplists:get_value(page_size, Options)}, {"PageNumber", proplists:get_value(page_number, Options)} ], Doc = mturk_xml_request(Config, "SearchQualificationTypes", Params), erlcloud_xml:decode( [ {num_results, "NumResults", integer}, {page_number, "PageNumber", integer}, {total_num_results, "TotalNumResults", integer}, {qualification_types, "QualificationType", fun extract_qualification_types/1} ], Doc ). -spec send_test_event_notification(proplist(), mturk_event_type()) -> ok | no_return(). send_test_event_notification(Notificaiton, TestEventType) -> send_test_event_notification(Notificaiton, TestEventType, default_config()). -spec send_test_event_notification(proplist(), mturk_event_type(), aws_config()) -> ok | no_return(). send_test_event_notification(Notification, TestEventType, Config) -> mturk_simple_request(Config, "SendTestEventNotification", [ {"Notification.Destination", proplists:get_value(destination, Notification)}, {"Notification.Transport", encode_transport(proplists:get_value(transport, Notification))}, {"Notification.Version", proplists:get_value(version, Notification, ?DEFAULT_NOTIFICATION_VERSION)}, {"Notification.EventType", encode_event_type(proplists:get_value(event_type, Notification))}, {"TestEventType", encode_event_type(TestEventType)} ] ). -spec set_hit_as_reviewing(string()) -> ok | no_return(). set_hit_as_reviewing(HITId) -> set_hit_as_reviewing(HITId, false). -spec set_hit_as_reviewing(string(), boolean() | aws_config()) -> ok | no_return(). set_hit_as_reviewing(HITId, Config) when is_record(Config, aws_config) -> set_hit_as_reviewing(HITId, false, Config); set_hit_as_reviewing(HITId, Revert) -> set_hit_as_reviewing(HITId, Revert, default_config()). -spec set_hit_as_reviewing(string(), boolean(), aws_config()) -> ok | no_return(). set_hit_as_reviewing(HITId, Revert, Config) -> mturk_simple_request(Config, "SetHITAsReviewing", [ {"HITId", HITId}, {"Revert", Revert} ] ). -spec set_hit_type_notification(string(), proplist()) -> ok | no_return(). set_hit_type_notification(HITTypeId, Notification) -> set_hit_type_notification(HITTypeId, Notification, undefined). -spec set_hit_type_notification(string(), proplist(), boolean() | undefined | aws_config()) -> ok | no_return(). set_hit_type_notification(HITTypeId, Notification, Config) when is_record(Config, aws_config) -> set_hit_type_notification(HITTypeId, Notification, undefined, Config); set_hit_type_notification(HITTypeId, Notification, Active) -> set_hit_type_notification(HITTypeId, Notification, Active, default_config()). -spec set_hit_type_notification(string(), proplist(), boolean() | undefined, aws_config()) -> ok | no_return(). set_hit_type_notification(HITTypeId, Notification, Active, Config) when is_list(HITTypeId), is_list(Notification), is_boolean(Active) orelse Active =:= undefined -> mturk_simple_request(Config, "SetHITTypeNotification", [ {"HITTypeId", HITTypeId}, {"Active", Active}, {"Notification.Destination", proplists:get_value(destination, Notification)}, {"Notification.Transport", encode_transport(proplists:get_value(transport, Notification))}, {"Notification.Version", proplists:get_value(version, Notification, ?DEFAULT_NOTIFICATION_VERSION)}, {"Notification.EventType", encode_event_type(proplists:get_value(event_type, Notification))} ] ). encode_event_type(assignment_accepted) -> "AssignmentAccepted"; encode_event_type(assignment_abandoned) -> "AssignmentAbandoned"; encode_event_type(assignment_returned) -> "AssignmentReturned"; encode_event_type(assignment_submitted) -> "AssignmentSubmitted"; encode_event_type(hit_reviewable) -> "HITReviewable"; encode_event_type(hit_expired) -> "HITExpired". encode_transport(email) -> "Email"; encode_transport(soap) -> "SOAP"; encode_transport(rest) -> "REST". -spec unblock_worker(string()) -> ok | no_return(). unblock_worker(WorkerId) -> unblock_worker(WorkerId, none). -spec unblock_worker(string(), string() | none | aws_config()) -> ok | no_return(). unblock_worker(WorkerId, Config) when is_record(Config, aws_config) -> unblock_worker(WorkerId, none, Config); unblock_worker(WorkerId, Reason) -> unblock_worker(WorkerId, Reason, default_config()). -spec unblock_worker(string(), string() | none, aws_config()) -> ok | no_return(). unblock_worker(WorkerId, Reason, Config) when is_list(WorkerId), is_list(Reason) orelse Reason =:= none -> mturk_simple_request(Config, "UnblockWorker", [{"WorkerId", WorkerId}, {"Reason", Reason}]). -spec update_qualification_score(string(), string(), integer()) -> ok | no_return(). update_qualification_score(QualificationTypeId, SubjectId, IntegerValue) -> update_qualification_score(QualificationTypeId, SubjectId, IntegerValue, default_config()). -spec update_qualification_score(string(), string(), integer(), aws_config()) -> ok | no_return(). update_qualification_score(QualificationTypeId, SubjectId, IntegerValue, Config) when is_list(SubjectId), is_list(QualificationTypeId), is_integer(IntegerValue) -> mturk_simple_request(Config, "UpdateQualificationScore", [ {"SubjectId", SubjectId}, {"QualificationTypeId", QualificationTypeId}, {"IntegerValue", IntegerValue} ] ). -spec update_qualification_type(#mturk_qualification_type{}) -> #mturk_qualification_type{} | no_return(). update_qualification_type(QType) -> update_qualification_type(QType, default_config()). -spec update_qualification_type(#mturk_qualification_type{}, aws_config()) -> #mturk_qualification_type{} | no_return(). update_qualification_type(QType, Config) -> Doc = mturk_xml_request(Config, "UpdateQualificationType", [ {"QualificationTypeId", QType#mturk_qualification_type.qualification_type_id}| qualification_type_params(QType) ] ), extract_qualification_type(Doc). encode_question_content(Items) -> [encode_xml(Item) || Item <- Items]. encode_xml_list(List) when is_list(List) -> [encode_xml(Item) || Item <- List]; encode_xml_list(undefined) -> []; encode_xml_list(XML) -> [encode_xml(XML)]. encode_xml({title, Title}) -> {'Title', [Title]}; encode_xml({text, Text}) -> {'Text', [Text]}; encode_xml({list, List}) -> {'List', [{'ListItem', [Item]} || Item <- List]}; encode_xml({formatted_content, Content}) -> {'FormattedContent', [#xmlText{value=Content, type=cdata}]}; encode_xml(#mturk_question_form{content=Content}) -> {'QuestionForm', [{xmlns, ?XMLNS_QUESTIONFORM}], encode_xml_list(Content)}; encode_xml(#mturk_overview{content=Content}) -> {'Overview', encode_xml_list(Content)}; encode_xml(#mturk_external_question{external_url=ExternalURL, frame_height=FrameHeight}) -> {'ExternalQuestion', [{xmlns, ?XMLNS_EXTERNALQUESTION}], [ {'ExternalURL', [ExternalURL]}, {'FrameHeight', [integer_to_list(FrameHeight)]} ]}; encode_xml(#mturk_question{question_identifier=QuestionId, display_name=DisplayName, is_required=IsRequired, question_content=Content, answer_specification=AnswerSpec}) -> {'Question', filter_undefined([ {'QuestionIdentifier', [QuestionId]}, {'DisplayName', [DisplayName]}, {'IsRequired', [atom_to_list(IsRequired)]}, {'QuestionContent', encode_question_content(Content)}, {'AnswerSpecification', [encode_xml(AnswerSpec)]} ])}; encode_xml(#mturk_answer_key{answers=Answers, qualification_value_mapping=QVMap}) -> {'AnswerKey', [{xmlns, ?XMLNS_ANSWERKEY}], encode_xml_list(Answers) ++ case QVMap of undefined -> []; _ -> [{'QualificationValueMapping', encode_xml_list(QVMap)}] end }; encode_xml(#mturk_test_answer{question_identifier=QId, answer_options=Opts, default_score=DefaultScore}) -> {'Question', [{'QuestionIdentifier', [QId]}] ++ encode_xml_list(Opts) ++ [{'DefaultScore', [integer_to_list(DefaultScore)]}] }; encode_xml(#mturk_answer_option{selection_identifier=SId, answer_score=Score}) -> {'AnswerOption', [ {'SelectionIdentifier', [SId]}, {'AnswerScore', [integer_to_list(Score)]} ]}; encode_xml(#mturk_percentage_mapping{maximum_summed_score=MScore}) -> {'PercentageMapping', [{'MaximumSummedScore', [integer_to_list(MScore)]}]}; encode_xml(#mturk_scale_mapping{summed_score_multiplier=SMult}) -> {'ScaleMapping', [{'SummedScoreMultiplier', [float_to_list(SMult)]}]}; encode_xml(#mturk_free_text_answer{constraints=C, default_text=Text, number_of_lines_suggestion=NLines}) -> {'FreeTextAnswer', [ encode_xml(C), {'DefaultText', case Text of undefined -> []; _ -> [Text] end}, {'NumberOfLinesSuggestion', [integer_to_list(NLines)]} ]}; encode_xml(#mturk_constraints{is_numeric=IsNumeric, min_value=MinValue, max_value=MaxValue, min_length=MinLength, max_length=MaxLength, answer_format_regex=AnswerFormatRegex, answer_format_regex_error_text=ErrorText, answer_format_regex_flags=Flags}) -> {'Constraints', lists:flatten([ case IsNumeric of true -> [{'IsNumeric', filter_undefined([{minValue, MinValue}, {maxValue, MaxValue}]), []}]; false -> [] end, if MinLength =/= undefined; MaxLength =/= undefined -> [{'Length', filter_undefined([{minLength, MinLength}, {maxLength, MaxLength}]), []}]; true -> [] end, case AnswerFormatRegex of undefined -> []; _ -> [{'AnswerFormatRegex', filter_undefined([{regex, AnswerFormatRegex}, {errorText, ErrorText}, {flags, Flags}]), []}] end ])}; encode_xml(#mturk_file_upload_answer{min_file_size_in_bytes=MinSize, max_file_size_in_bytes=MaxSize}) -> {'FileUploadAnswer', [ {'MaxFileSizeInBytes', [integer_to_list(MaxSize)]}, {'MinFileSizeInBytes', [integer_to_list(MinSize)]} ]}; encode_xml(#mturk_selection_answer{ min_selection_count=MinSCount, max_selection_count=MaxSCount, style_suggestion=StyleSuggestion, selections=Selections}) -> {'SelectionAnswer', filter_undefined([ {'MinSelectionCount', [integer_to_list(MinSCount)]}, {'MaxSelectionCount', [integer_to_list(MaxSCount)]}, {'StyleSuggestion', case StyleSuggestion of none -> undefined; _ -> [atom_to_list(StyleSuggestion)] end} ]) ++ [{'Selections', encode_xml_list(Selections)}]}; encode_xml(#mturk_selection{selection_identifier=SId, text=Text, formatted_content=Content, binary=Binary}) -> {'Selection', filter_undefined([ {'SelectionIdentifier', [SId]}, {'Text', [Text]}, {'FormattedContent', [Content]} ]) ++ encode_xml_list(Binary)}; encode_xml(#mturk_java_applet{applet_path=AP, applet_filename=AF, width=Width, height=Height, application_parameters=Params}) -> {'JavaApplet', [ {'AppletPath', [AP]}, {'AppletFilename', [AF]}, {'Width', [integer_to_list(Width)]}, {'Height', [integer_to_list(Height)]}| [{'ApplicationParameter', [{'Name', [Name]}, {'Value', [Value]}]} || {Name, Value} <- Params] ]}; encode_xml(#mturk_flash{flash_movie_url=URL, width=Width, height=Height, application_parameters=Params}) -> {'FlashMovie', [ {'FlashMovieURL', [URL]}, {'Width', [integer_to_list(Width)]}, {'Height', [integer_to_list(Height)]}| [{'ApplicationParameter', [{'Name', [Name]}, {'Value', [Value]}]} || {Name, Value} <- Params] ]}; encode_xml(#mturk_binary{mime_type=MT, data_url=DataURL, alt_text=AltText}) -> {'Binary', [encode_xml(MT), {'DataURL', [DataURL]}, {'AltText', [AltText]} ]}; encode_xml(#mturk_mime_type{type=T, sub_type=ST}) -> {'MimeType', [{'Type', [T]}, {'SubType', [ST]}]}; encode_xml(#mturk_embedded_binary{embedded_mime_type=#mturk_mime_type{type=T, sub_type=ST}, data_url=DataURL, alt_text=AltText, width=Width, height=Height, application_parameters=Params}) -> {'EmbeddedBinary', [ {'EmbeddedMimeType', [{'Type', [T]}, {'SubType', [ST]}]}, {'DataURL', [DataURL]}, {'AltText', [AltText]}, {'Width', [integer_to_list(Width)]}, {'Height', [integer_to_list(Height)]}| [{'ApplicationParameter', [{'Name', [Name]}, {'Value', [Value]}]} || {Name, Value} <- Params] ]}; encode_xml(undefined) -> undefined. xml_to_string(undefined) -> undefined; xml_to_string(XML) -> "" ++ XMLString = lists:flatten(xmerl:export_simple([XML], xmerl_xml)), XMLString. encode_qualification_type_status(active) -> "Active"; encode_qualification_type_status(inactive) -> "Inactive". decode_qualification_type_status("Active") -> active; decode_qualification_type_status("Inactive") -> inactive; decode_qualification_type_status("Disposing") -> disposing. filter_undefined(List) -> [Elem || {_, Value} = Elem <- List, Value =/= undefined, Value =/= [undefined]]. mturk_simple_request(Config, Operation, Params) -> Doc = mturk_xml_request(Config, Operation, Params), case erlcloud_xml:get_text("//Request/IsValid", Doc) of "True" -> ok; "False" -> ErrorCode = erlcloud_xml:get_text("//Request/Errors/Error[1]/Code", Doc), ErrorMessage = erlcloud_xml:get_text("//Request/Errors/Error[1]/Message", Doc), erlang:error({mturk_error, ErrorCode, ErrorMessage}) end. mturk_xml_request(Config, Operation, Params) -> Doc = element(1, xmerl_scan:string(mturk_request(Config, Operation, Params))), Request = hd(xmerl_xpath:string("//Request", Doc)), case erlcloud_xml:get_text("IsValid", Request) of "True" -> hd(xmerl_xpath:string(atom_to_list(element(1,hd(Request#xmlElement.parents))), Doc)); "False" -> ErrorCode = erlcloud_xml:get_text("//Request/Errors/Error[1]/Code", Doc), ErrorMessage = erlcloud_xml:get_text("//Request/Errors/Error[1]/Message", Doc), erlang:error({mturk_error, ErrorCode, ErrorMessage}) end. mturk_request(Config, Operation, Params) -> Timestamp = erlcloud_aws:format_timestamp(erlang:universaltime()), StringToSign = [?API_SERVICE, Operation, Timestamp], Signature = base64:encode(erlcloud_util:sha_mac(Config#aws_config.secret_access_key, StringToSign)), QParams = [{"Operation", Operation}, {"Version", ?API_VERSION}, {"Service", ?API_SERVICE}, {"Timestamp", Timestamp}, {"AWSAccessKeyId", Config#aws_config.access_key_id}, {"Signature", Signature}|Params], URL = ["https://", Config#aws_config.mturk_host, "/"], Response = erlcloud_httpc:request( lists:flatten(URL), post, [{<<"content-type">>, <<"application/x-www-form-urlencoded">>}], list_to_binary(erlcloud_http:make_query_string(QParams)), erlcloud_aws:get_timeout(Config), Config), case Response of {ok, {{200, _StatusLine}, _Headers, Body}} -> binary_to_list(Body); {ok, {{Status, _StatusLine}, _Headers, _Body}} -> erlang:error({aws_error, {http_error, Status, _StatusLine, _Body}}); {error, Error} -> erlang:error({aws_error, {socket_error, Error}}) end.