Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion openreview/arr/arr.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,14 @@ def setup_committee_matching(self, committee_id=None, compute_affinity_scores=Fa
return self.venue.setup_committee_matching(committee_id, compute_affinity_scores, compute_conflicts, compute_conflicts_n_years, alternate_matching_group, submission_track)

def set_assignments(self, assignment_title, committee_id, enable_reviewer_reassignment=False, overwrite=False):
return self.venue.set_assignments(assignment_title, committee_id, enable_reviewer_reassignment, overwrite)
match_group = self.client.get_group(committee_id)
assignment_invitation = self.client.get_invitation(self.get_assignment_id(match_group.id))
conference_matching = matching.Matching(
self,
match_group,
submission_content=assignment_invitation.edit.get('head', {}).get('param', {}).get('withContent')
)
return conference_matching.deploy(assignment_title, overwrite, enable_reviewer_reassignment)

def unset_assignments(self, assignment_title, committee_id):
return self.venue.unset_assignments(assignment_title, committee_id)
Expand Down
50 changes: 50 additions & 0 deletions openreview/arr/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,31 @@

from openreview.stages.default_content import comment_v2


def update_emergency_assignment_deadline(client, venue, venue_id, emergency_assignment_deadline):
if not emergency_assignment_deadline:
return

group_client = venue.client if hasattr(venue, 'client') and hasattr(venue.client, 'post_group_edit') else client
parsed_deadline = openreview.tools.datetime.datetime.strptime(
emergency_assignment_deadline,
'%Y/%m/%d %H:%M'
)
group_client.post_group_edit(
invitation=venue.get_meta_invitation_id(),
readers=[venue.id],
writers=[venue.id],
signatures=[venue.id],
group=openreview.api.Group(
id=venue_id,
content={
'emergency_assignment_deadline': {
'value': openreview.tools.datetime_millis(parsed_deadline)
}
}
)
)

class ARRWorkflow(object):
UPDATE_WAIT_TIME = 5000
DEFAULT_AUTHOR_RESPONSE_EXTENSION_CRON = '0 */12 * * *'
Expand Down Expand Up @@ -172,6 +197,12 @@ class ARRWorkflow(object):
"order": 18,
"required": False
},
"emergency_assignment_deadline": {
"description": "Assignments made on or after this date are marked as emergency.",
"value-regex": "^[0-9]{4}\\/([1-9]|0[1-9]|1[0-2])\\/([1-9]|0[1-9]|[1-2][0-9]|3[0-1])(\\s+)?((2[0-3]|[01][0-9]|[0-9]):[0-5][0-9])?(\\s+)?$",
"order": 58,
"required": False
},
"ae_checklist_start_date": {
"description": "When should the action editor checklist open?",
"value-regex": "^[0-9]{4}\\/([1-9]|0[1-9]|1[0-2])\\/([1-9]|0[1-9]|[1-2][0-9]|3[0-1])(\\s+)?((2[0-3]|[01][0-9]|[0-9]):[0-5][0-9])?(\\s+)?$",
Expand Down Expand Up @@ -1412,6 +1443,25 @@ def __init__(self, client_v2, venue, configuration_note, request_form_id, suppor
invitation=emg_score_inv
)

if role in [venue.get_reviewers_id(), venue.get_area_chairs_id()] and not openreview.tools.get_invitation(self.client_v2, f"{role}/-/Type"):
m._create_edge_invitation(f"{role}/-/Type")
type_inv = self.client_v2.get_invitation(f"{role}/-/Type")
type_inv.edit['weight']['param']['optional'] = True
type_inv.edit['label'] = {
"param": {
"regex": ".*",
"optional": True,
"deletable": True
}
}
self.client_v2.post_invitation_edit(
invitations=venue.get_meta_invitation_id(),
readers=[venue.id],
writers=[venue.id],
signatures=[venue.id],
invitation=type_inv
)

for name in edge_invitation_names:
if not openreview.tools.get_invitation(self.client_v2, f"{role}/-/{name}"):
cmp_inv = self.client_v2.get_invitation(venue.get_custom_max_papers_id(m.match_group.id))
Expand Down
20 changes: 18 additions & 2 deletions openreview/arr/invitation.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,24 @@ def set_submission_metadata_revision_invitation(self, arr_stage):
self.save_invitation(invitation, replacement=False)
return invitation

def set_assignment_invitation(self, committee_id, submission_content=None):
return self.venue_invitation_builder.set_assignment_invitation(committee_id, submission_content)
def set_assignment_invitation(self, committee_id, submission_content=None, cdate=None):
self.venue_invitation_builder.set_assignment_invitation(
committee_id,
submission_content=submission_content,
cdate=cdate
)
invitation = self.client.get_invitation(self.venue.get_assignment_id(committee_id, deployed=True))

committee_name = self.venue.get_committee_name(committee_id)
if committee_name not in self.venue.reviewer_roles and committee_name not in self.venue.area_chair_roles:
return invitation

arr_process = self.get_process_content('process/assignment_post_process.py')
if invitation.process == arr_process:
return invitation

invitation.process = arr_process
return self.save_invitation(invitation, replacement=True)

def set_group_matching_setup_invitations(self, committee_id):
return self.venue_invitation_builder.set_group_matching_setup_invitations(committee_id)
Expand Down
119 changes: 119 additions & 0 deletions openreview/arr/process/assignment_post_process.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
def process_update(client, edge, invitation, existing_edge):
import openreview

domain = client.get_group(edge.domain)
venue_id = domain.id
meta_invitation_id = domain.content['meta_invitation_id']['value']
short_phrase = domain.content['subtitle']['value']
contact = domain.content['contact']['value']
program_chairs_id = domain.content['program_chairs_id']['value']
submission_name = domain.content['submission_name']['value']
reviewers_name = invitation.content['reviewers_name']['value']
reviewers_id = invitation.content['reviewers_id']['value']
sync_sac_id = invitation.content.get('sync_sac_id', {}).get('value')
sac_assignment_id = invitation.content.get('sac_assignment_id', {}).get('value')
sender = domain.get_content_value('message_sender')
pretty_name = openreview.tools.pretty_id(reviewers_name)
pretty_name = pretty_name[:-1] if pretty_name.endswith('s') else pretty_name

note = client.get_note(edge.head)
group = client.get_group(f'{venue_id}/{submission_name}{note.number}/{reviewers_name}')
if edge.ddate and edge.tail in group.members:
assignment_edges = client.get_edges(invitation=edge.invitation, head=edge.head, tail=edge.tail)
if assignment_edges:
return
print(f'Remove member {edge.tail} from {group.id}')
client.remove_members_from_group(group.id, edge.tail)

if sync_sac_id and sync_sac_id.format(number=note.number) not in edge.signatures:
print('Remove member from SAC group')
assignments = client.get_edges(invitation=sac_assignment_id, head=edge.tail)
if assignments:
client.remove_members_from_group(sync_sac_id.format(number=note.number), assignments[0].tail)
else:
print('No SAC assignments found')

if not edge.ddate and edge.tail not in group.members:
print(f'Add member {edge.tail} to {group.id}')
client.add_members_to_group(group.id, edge.tail)
client.add_members_to_group(reviewers_id, edge.tail)

if sync_sac_id:
print('Add the SAC to the paper group')
assignments = client.get_edges(invitation=sac_assignment_id, head=edge.tail)
if assignments:
client.add_members_to_group(sync_sac_id.format(number=note.number), assignments[0].tail)
else:
print('No SAC assignments found')

signature = openreview.tools.pretty_id(edge.signatures[0])
if venue_id in edge.signatures or program_chairs_id in edge.signatures:
signature = openreview.tools.pretty_id(program_chairs_id)

subject = f'[{short_phrase}] You have been assigned as a {pretty_name} for paper number {note.number}'
message = f'''This is to inform you that you have been assigned as a {pretty_name} for paper number {note.number} for {short_phrase}.

To review this new assignment, please login to OpenReview and go to https://openreview.net/forum?id={note.forum}.

To check all of your assigned papers, go to https://openreview.net/group?id={reviewers_id}.

Thank you,

{signature}'''

client.post_message(
subject,
[edge.tail],
message,
invitation=meta_invitation_id,
signature=venue_id,
parentGroup=group.id,
replyTo=contact,
sender=sender
)

# ----- ARR-specific logic -----
deadline = domain.content.get('emergency_assignment_deadline', {}).get('value')
if deadline is None:
return

type_invitation_id = f"{edge.invitation.split('/-/')[0]}/-/Type"
if edge.ddate:
client.delete_edges(
invitation=type_invitation_id,
head=edge.head,
tail=edge.tail,
wait_to_finish=True,
soft_delete=True
)
return

assignment_timestamp = edge.tcdate
## clear type edges in case
if assignment_timestamp < deadline:
client.delete_edges(
invitation=type_invitation_id,
head=edge.head,
tail=edge.tail,
wait_to_finish=True,
soft_delete=True
)
return
else:
existing_type_edges = client.get_edges(
invitation=type_invitation_id,
head=edge.head,
tail=edge.tail
)
if existing_type_edges:
return

client.post_edge(
openreview.api.Edge(
invitation=type_invitation_id,
signatures=[domain.id],
head=edge.head,
tail=edge.tail,
label='Emergency'
)
)
9 changes: 8 additions & 1 deletion openreview/arr/process/configuration_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,11 @@ def process(client, note, invitation):
support_group = request_form.invitation.split('/-/')[0]
venue = openreview.helpers.get_conference(client, request_form_id, support_group)

venue.set_arr_stages(note)
openreview.arr.update_emergency_assignment_deadline(
client,
venue,
venue_id,
note.content.get('emergency_assignment_deadline')
)

venue.set_arr_stages(note)
3 changes: 3 additions & 0 deletions openreview/arr/webfield/areachairsWebfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ browseProposedInvitations.push(`${reviewerGroup}/-/Seniority,head:ignore`)
browseInvitations.push(`${reviewerGroup}/-/Status`)
browseProposedInvitations.push(`${reviewerGroup}/-/Status`)

browseInvitations.push(`${reviewerGroup}/-/Type`)
browseProposedInvitations.push(`${reviewerGroup}/-/Type`)

browseInvitations.push(`${reviewerGroup}/-/Emergency_Score`)
browseProposedInvitations.push(`${reviewerGroup}/-/Emergency_Score`)

Expand Down
2 changes: 2 additions & 0 deletions openreview/arr/webfield/programChairsWebfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const preferredEmailInvitationId = domain.content.preferred_emails_id?.value
const browseInvitations = [
domain.content.reviewers_affinity_score_id?.value,
domain.content.reviewers_conflict_id?.value,
`${reviewersId}/-/Type`,
`${reviewersId}/-/Emergency_Score`,
`${reviewersId}/-/Research_Area`,
`${reviewersId}/-/Status`,
Expand Down Expand Up @@ -40,6 +41,7 @@ if (areaChairName) {
const browseInvitations = [
domain.content.area_chairs_affinity_score_id?.value,
domain.content.area_chairs_conflict_id?.value,
`${areaChairsId}/-/Type`,
`${areaChairsId}/-/Emergency_Score`,
`${areaChairsId}/-/Research_Area`,
`${areaChairsId}/-/Status`,
Expand Down
2 changes: 2 additions & 0 deletions openreview/arr/webfield/seniorAreaChairsWebfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const preferredEmailInvitationId = domain.content.preferred_emails_id?.value
const browseAreaChairInvitations = [
`${areaChairsId}/-/Agreggate_Score`,
domain.content.area_chairs_affinity_score_id?.value,
`${areaChairsId}/-/Type`,
`${areaChairsId}/-/Emergency_Score`,
`${areaChairsId}/-/Research_Area`,
].join(';')
Expand All @@ -37,6 +38,7 @@ assignmentUrls[domain.content.area_chairs_name?.value] = {
const browseReviewerInvitations = [
domain.content.reviewers_affinity_score_id?.value,
domain.content.reviewers_conflict_id?.value,
`${reviewersId}/-/Type`,
`${reviewersId}/-/Research_Area`,
`${reviewersId}/-/Status`,
`${reviewersId}/-/Emergency_Score`,
Expand Down
3 changes: 3 additions & 0 deletions openreview/venue/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ def create_venue_group(self):
if venue_group.content.get('reviewers_proposed_assignment_title'):
content['reviewers_proposed_assignment_title'] = venue_group.content.get('reviewers_proposed_assignment_title')

if venue_group.content.get('emergency_assignment_deadline'):
content['emergency_assignment_deadline'] = venue_group.content.get('emergency_assignment_deadline')

if venue_group.content.get('allow_gurobi_solver'):
content['allow_gurobi_solver'] = venue_group.content.get('allow_gurobi_solver')

Expand Down
Loading