This repository has been archived by the owner on Mar 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 569
/
group_assignment_invitations_controller.rb
251 lines (204 loc) · 7.43 KB
/
group_assignment_invitations_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# frozen_string_literal: true
class GroupAssignmentInvitationsController < ApplicationController
class InvalidStatusForRouteError < StandardError; end
include InvitationsControllerMethods
layout "layouts/invitations"
before_action :route_based_on_status, only: %i[setup successful_invitation]
before_action :check_user_not_group_member, only: :show
before_action :check_should_redirect_to_roster_page, only: :show
before_action :authorize_group_access, only: :accept_invitation
before_action :ensure_github_repo_exists, only: :successful_invitation
before_action :check_group_exists, only: :accept
def show
@groups = invitation.groups.order(:title).page(params[:page])
end
def accept; end
def accept_assignment
create_group_assignment_repo do
redirect_to successful_invitation_group_assignment_invitation_path
end
end
def accept_invitation
selected_group = Group.find_by(id: group_params[:id])
selected_group_title = group_params[:title]
validate_max_teams_not_exceeded! unless selected_group
create_group_assignment_repo(selected_group: selected_group, new_group_title: selected_group_title) do
redirect_to successful_invitation_group_assignment_invitation_path
end
end
def setup; end
# rubocop:disable Metrics/AbcSize
# rubocop:disable MethodLength
def create_repo
job_started =
if group_invite_status.accepted? || group_invite_status.errored?
if repo_ready?
group_invite_status.completed!
false
else
group_assignment_repo&.destroy
@group_assignment_repo = nil
report_retry
group_invite_status.waiting!
CreateGitHubRepositoryNewJob.perform_later(group_assignment, group, retries: 3)
true
end
else
false
end
render json: {
job_started: job_started,
status: group_invite_status.status,
repo_url: group_assignment_repo&.github_repository&.html_url
}
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable MethodLength
def progress
render json: {
status: group_invite_status&.status,
repo_url: group_assignment_repo&.github_repository&.html_url
}
end
def successful_invitation; end
def join_roster
super
redirect_to group_assignment_invitation_url(invitation)
rescue ActiveRecord::ActiveRecordError
flash[:error] = "An error occurred, please try again!"
end
private
def required_scopes
GitHubClassroom::Scopes::GROUP_ASSIGNMENT_STUDENT
end
def group_params
params
.require(:group)
.permit(:id, :title)
end
## Before Actions
# rubocop:disable Metrics/AbcSize
# rubocop:disable MethodLength
def route_based_on_status
status = group_invite_status&.status
case status
when "unaccepted", nil
redirect_to group_assignment_invitation_path(invitation)
when "completed"
redirect_to successful_invitation_group_assignment_invitation_path if action_name != "successful_invitation"
when *(GroupInviteStatus::ERRORED_STATUSES + GroupInviteStatus::SETUP_STATUSES)
redirect_to setup_group_assignment_invitation_path if action_name != "setup"
else
raise InvalidStatusForRouteError, "No route registered for status: #{status}"
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable MethodLength
def authorize_group_access
group_id = group_params[:id]
return if group_id.blank?
group = Group.find(group_id)
validate_max_members_not_exceeded!(group)
return if group_assignment.grouping.groups.find_by(id: group_id)
report_invitation_failure
raise NotAuthorized, "You are not permitted to select this team"
end
def check_user_not_group_member
return if group.blank?
redirect_to accept_group_assignment_invitation_path
end
def ensure_github_repo_exists
return not_found unless group_assignment_repo
return if group_assignment_repo
.github_repository
.present?(headers: GitHub::APIHeaders.no_cache_no_store)
group = group_assignment_repo.group
group_assignment_repo.destroy
@group_assignment_repo = nil
create_group_assignment_repo(selected_group: group)
end
## Controller Method Helpers
# rubocop:disable Metrics/AbcSize
def validate_max_members_not_exceeded!(group)
return unless group.present? && group_assignment.present? && group_assignment.max_members.present?
return unless group.repo_accesses.count >= group_assignment.max_members
report_invitation_failure
raise NotAuthorized, "This team has reached its maximum member limit of #{group_assignment.max_members}."
end
def validate_max_teams_not_exceeded!
return unless group_assignment.present? && group_assignment.max_teams.present?
return unless group_assignment.grouping.groups.count >= group_assignment.max_teams
report_invitation_failure
raise NotAuthorized, "This assignment has reached its team limit of #{group_assignment.max_teams}."\
" Please join an existing team."
end
# rubocop:enable Metrics/AbcSize
# rubocop:disable Metrics/AbcSize
# rubocop:disable MethodLength
def create_group_assignment_repo(selected_group: group, new_group_title: nil)
result = invitation.redeem_for(
current_user,
selected_group,
new_group_title
)
case result.status
when :failed
report_invitation_failure if invitation.enabled?
flash[:error] = result.error
redirect_to group_assignment_invitation_path
when :success, :pending
GitHubClassroom.statsd.increment("group_exercise_invitation.accept")
route_based_on_status
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable MethodLength
## Datadog reporting convenience methods
def report_retry
if group_invite_status.errored_creating_repo?
GitHubClassroom.statsd.increment("group_exercise_repo.create.retry")
elsif group_invite_status.errored_importing_starter_code?
GitHubClassroom.statsd.increment("group_exercise_repo.import.retry")
end
end
def report_invitation_failure
GitHubClassroom.statsd.increment("group_exercise_invitation.fail")
end
## Resource Helpers
def group
repo_access = current_user.repo_accesses.find_by(organization: organization)
return unless repo_access.present? && repo_access.groups.present?
@group ||= repo_access.groups.find_by(grouping: group_assignment.grouping)
end
helper_method :group
def group_invite_status
return if group.blank?
@group_invite_status ||= invitation.status(group)
end
def group_assignment
@group_assignment ||= invitation.group_assignment
end
helper_method :group_assignment
def group_assignment_repo
@group_assignment_repo ||= GroupAssignmentRepo.find_by(group_assignment: group_assignment, group: group)
end
helper_method :group_assignment_repo
def invitation
@invitation ||= GroupAssignmentInvitation
.includes(group_assignment: :group_assignment_repos)
.find_by!(key: params[:id])
end
helper_method :invitation
def organization
@organization ||= group_assignment.organization
end
helper_method :organization
def repo_ready?
return false if group_assignment_repo.blank?
return false if group_assignment.starter_code? && !group_assignment_repo.github_repository.imported?
true
end
def check_group_exists
redirect_to group_assignment_invitation_path(invitation) if group.blank?
end
end