@@ -40,6 +40,7 @@ object MTurkMethods {
40
40
tg.head._1
41
41
}
42
42
43
+ // Handle the user manual qualification requests
43
44
private [worker] def mturk_grantQualifications (hitstate : HITState , state : MTState , backend : AmazonMTurk ) : MTState = {
44
45
var internal_state = state
45
46
@@ -68,20 +69,27 @@ object MTurkMethods {
68
69
if (internal_state.worker_whitelist.contains(worker_id, group_id)) {
69
70
// if that disqualification is not the same as the one they're asking for, sorry, reject;
70
71
// granting this would violate i.i.d. guarantee
72
+ // note by Ye Shu: this is the case where disqualification has been granted for previous batch
71
73
if (internal_state.getHITTypeForWhitelistedWorker(worker_id, group_id).id != hit_type_id) {
72
74
backend.rejectQualificationRequest(new model.RejectQualificationRequestRequest ()
73
75
.withQualificationRequestId(request.getQualificationRequestId)
74
76
.withReason(" You have already requested a qualification or submitted work for an associated HITType " +
75
77
" that disqualifies you from participating in this HITType." ))
76
78
// otherwise, they're requesting something we've already granted; reject
77
79
} else {
80
+ // note by Ye Shu: this is the case where disqualification has been granted for this branch
78
81
backend.rejectQualificationRequest(new model.RejectQualificationRequestRequest ()
79
82
.withQualificationRequestId(request.getQualificationRequestId)
80
83
.withReason(" You cannot request this qualification more than once." )
81
84
)
82
85
}
83
86
} else {
84
87
// if we don't know them, record the user and grant their disqualification request
88
+ // note by Ye Shu: this code is unlikely to be reached, because we are now using qualification requirement
89
+ // that "xxx has not been granted". So if a worker asks for qualification, they are likely already disqualified
90
+ // However I'm keeping this code here just in case
91
+ DebugLog (s " Granting qualification request: (worker ID: ${worker_id}, group ID: ${group_id}). " , LogLevelInfo (), LogType .ADAPTER , null )
92
+
85
93
internal_state = internal_state.updateWorkerWhitelist(worker_id, group_id, hit_type_id)
86
94
// get the BatchKey associated with the HITType; guaranteed to exist
87
95
val batchKey = internal_state.getBatchKeyByHITTypeId(hit_type_id).get
@@ -97,35 +105,44 @@ object MTurkMethods {
97
105
internal_state
98
106
}
99
107
108
+ /**
109
+ * Creates `QualificationRequirement` for a question.
110
+ *
111
+ * This QualificationRequirement is then reused for the entire question.
112
+ * It'll be set when a worker answers a question, so the worker will not be
113
+ * able to answer the recreated question in future batches.
114
+ */
100
115
private [worker] def mturk_createQualification (title : String ,
101
116
batchKey : BatchKey ,
102
117
batch_no : Int ,
103
- backend : AmazonMTurk ) : QualificationRequirement = {
118
+ backend : AmazonMTurk ): QualificationRequirement = {
104
119
// get a simply-formatted date
105
120
val sdf = new SimpleDateFormat (" yyyy-MM-dd:z" )
106
121
val datestr = sdf.format(new Date ())
107
122
108
- val qualtxt = s " AutoMan automatically generated Disqualification (title: $title, date: $datestr, batchKey: $batchKey, batch_no: $batch_no) "
109
- // val qualRequest = new CreateQualificationTypeRequest()()
110
- // qualRequest.setName("AutoMan").setKeywords()
111
- // val id : UUID = UUID.randomUUID()
112
- val qual = backend.createQualificationType(new CreateQualificationTypeRequest ()
113
- // .withName("AutoMan")
114
- .withName(" Automan " + UUID .randomUUID().toString)
115
- // .setDescription(UUID.randomUUID())
123
+ // Creates qualification type
124
+ val qualID : QualificationID = {
125
+ val qualtxt = s " AutoMan automatically generated Disqualification (title: \" $title\" , date: $datestr) " // , groupID: ${batchKey._1}
126
+ // Commented out groupID in qualtxt since groupID is just title now.
127
+
128
+ val qual = backend.createQualificationType(new CreateQualificationTypeRequest ()
129
+ .withName(qualtxt)
116
130
.withKeywords(" automan" )
117
- .withDescription(qualtxt)
131
+ .withDescription(s " Automan ${ UUID .randomUUID().toString} : $ qualtxt" )
118
132
// .withQualificationTypeStatus(QualificationTypeStatus.Inactive)
119
133
.withQualificationTypeStatus(QualificationTypeStatus .Active )
120
- ) : CreateQualificationTypeResult // UUID keyword?
121
- // "AutoMan " + UUID.randomUUID(), "automan", qualtxt)
134
+ ) : CreateQualificationTypeResult // UUID keyword?
135
+
136
+ DebugLog (s " Created disqualification type ID: ${qual.getQualificationType.getQualificationTypeId}. " ,LogLevelInfo (),LogType .ADAPTER ,null )
137
+ qual.getQualificationType.getQualificationTypeId
138
+ }
122
139
123
- DebugLog ( s " Creating disqualification ID: ${qual.getQualificationType.getQualificationTypeId} . " , LogLevelInfo (), LogType . ADAPTER , null )
140
+ // Creates Qualification Requirement
124
141
new QualificationRequirement ()
125
- .withQualificationTypeId(qual.getQualificationType.getQualificationTypeId )
142
+ .withQualificationTypeId(qualID )
126
143
.withComparator(model.Comparator .DoesNotExist )
127
144
// .withIntegerValues(batch_no)
128
- .withActionsGuarded(" Accept" ) // TODO: Check if this is what we want
145
+ .withActionsGuarded(" Accept" )
129
146
130
147
// model.Comparator.EqualTo, batch_no, null, false)
131
148
}
@@ -238,23 +255,21 @@ object MTurkMethods {
238
255
// get just-created batch number; guaranteed to exist because we just created it
239
256
val batch_no = internal_state.getBatchNo(batch_key).get
240
257
241
- // create disqualification for batch
258
+ // create disqualification for question
259
+ // if already exists (i.e. not first batch) then reuse disqualification
260
+ // This disqualification ensures that the question and its recreated version
261
+ // (with longer worker timeouts) are only answered once maximum by each worker
242
262
// TODO: tinker with imports
243
- val disqualification : QualificationRequirement = mturk_createQualification(title, batch_key, batch_no, backend)
244
- DebugLog (s " Created disqualification ${disqualification.getQualificationTypeId} for batch key = " + batch_key, LogLevelDebug (), LogType .ADAPTER , null )
263
+ val disqualification : QualificationRequirement =
264
+ internal_state.qualificationRequirements.getOrElse(group_id, {
265
+ val qual = mturk_createQualification(title, batch_key, batch_no, backend)
266
+ DebugLog (s " Created new disqualification with type ID ${qual.getQualificationTypeId} for group id " + group_id, LogLevelInfo (), LogType .ADAPTER , null )
267
+ // update qualifications so it can be reused for future batches
268
+ internal_state = internal_state.addQualificationRequirement(group_id, qual)
269
+ qual
270
+ })
245
271
// getQTId is in the doc...
246
272
247
- // whenever we create a new group, we need to add the disqualification to the HITType
248
- // EXCEPT if it's the very first time the group is posted
249
- val qs : util.Collection [QualificationRequirement ] =
250
- if (batch_no != 1 ) {
251
- DebugLog (s " Batch # ${batch_no} run, using disqualification ${disqualification.getQualificationTypeId} for batch " + batch_key, LogLevelDebug (), LogType .ADAPTER , null )
252
- List (disqualification)
253
- } else {
254
- DebugLog (s " Batch # ${batch_no} run, using no qualifications for batch " + batch_key, LogLevelDebug (), LogType .ADAPTER , null )
255
- Nil
256
- }
257
-
258
273
val autoApprovalDelayInSeconds = (3 * 24 * 60 * 60 ).toLong // 3 days
259
274
260
275
val hit_type_id = backend.createHITType(new CreateHITTypeRequest ()
@@ -264,7 +279,7 @@ object MTurkMethods {
264
279
.withTitle(title) // title
265
280
.withKeywords(keywords.mkString(" ," )) // keywords
266
281
.withDescription(desc) // description
267
- .withQualificationRequirements(qs) // qualifications
282
+ .withQualificationRequirements(List (disqualification)) // qualifications
268
283
)
269
284
val hittype = HITType (hit_type_id.getHITTypeId, disqualification, group_id)
270
285
0 commit comments