Skip to content
This repository was archived by the owner on Mar 29, 2022. It is now read-only.

User management #464

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
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
50 changes: 50 additions & 0 deletions app/controllers/management_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

class ManagementController < ApplicationController
before_action :require_user_logged_in!
before_action :require_user_moderator!
before_action :find_user_by_uid, only: [:show, :update, :ban, :unban]

def index
@flagged_users = User.where(system_flagged: true, moderator_banned: false)
.order(system_flagged_at: :desc)
@banned_users = User.where(moderator_banned: true)
.order(system_flagged: :asc, moderator_banned_at: :desc)
end

def show
p @user
end

def update
@user.assign_attributes(params_for_update)
@user.save
redirect_to management_user_path(@user.uid)
end

def ban
@user.ban
redirect_to management_user_path(@user.uid)
end

def unban
@user.unban
redirect_to management_user_path(@user.uid)
end

private

def params_for_update
params.require(:user).permit(:is_moderator, :moderator_notes)
end

def require_user_moderator!
unless current_user.is_moderator?
render plain: 'not-authorized', status: :unauthorized
end
end

def find_user_by_uid
@user = User.find_by(uid: params[:user_uid])
end
end
59 changes: 57 additions & 2 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class User < ApplicationRecord
# rubocop:disable Metrics/BlockLength, Layout/MultilineHashBraceLayout
state_machine initial: :new do
event :register do
transition new: :registered
transition %i[new unbanned] => :registered
end

event :wait do
Expand Down Expand Up @@ -47,6 +47,14 @@ class User < ApplicationRecord
transition incompleted: :completed
end

event :ban do
transition %i[registered waiting] => :banned
end

event :unban do
transition banned: :unbanned
end

state all - [:new] do
validates :terms_acceptance, acceptance: true
validates :email, presence: true
Expand All @@ -60,7 +68,7 @@ class User < ApplicationRecord
validates :sticker_coupon, absence: true
end

state all - %i[new registered waiting] do
state all - %i[new registered waiting banned unbanned] do
validates :receipt, presence: true
end

Expand Down Expand Up @@ -128,13 +136,35 @@ def gift
after_transition to: :completed do |user, _transition|
user.win
end

after_transition to: :banned do |user, _transition|
user.moderator_banned = true
user.moderator_banned_at = Time.zone.now
user.save!
end

after_transition to: :unbanned do |user, _transition|
user.moderator_banned = false
user.moderator_banned_at = Time.zone.now
user.save!
user.register
TryUserTransitionService.call(user)
end
end
# rubocop:enable Metrics/BlockLength, Layout/MultilineHashBraceLayout

def pull_requests
pull_request_service.all
end

def spam_repo_pull_requests_count
pull_request_service.spam_repo_prs.count
end

def invalid_label_pull_requests_count
pull_request_service.invalid_label_prs.count
end

def waiting_pull_requests_count
pull_request_service.waiting_prs.count
end
Expand Down Expand Up @@ -179,10 +209,35 @@ def completed_or_won?
completed? || won_shirt? || won_sticker?
end

def check_flagged_state
should_flag = should_be_flagged?

unless system_flagged == should_flag
self.system_flagged_at = Time.zone.now
self.system_flagged = should_flag
save!
end

return if moderator_banned?

if should_be_banned? and ban
self.moderator_notes = "#{moderator_notes} User automatically banned by system.".strip
save!
end
end

delegate :assign_coupon, to: :coupon_service

private

def should_be_flagged?
invalid_label_pull_requests_count + spam_repo_pull_requests_count >= 2
end

def should_be_banned?
invalid_label_pull_requests_count + spam_repo_pull_requests_count >= 4
end

def github_emails
UserEmailService.new(self).emails
end
Expand Down
4 changes: 4 additions & 0 deletions app/presenters/profile_page_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ def initialize(user)
@user = user
end

def show_banned_message?
@user.banned?
end

def display_pre_launch?
Hacktoberfest.pre_launch?
end
Expand Down
8 changes: 8 additions & 0 deletions app/services/pull_request_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ def all
prs
end

def spam_repo_prs
all.select(&:spam_repo?)
end

def invalid_label_prs
all.select(&:invalid_label?)
end

def waiting_prs
all.select(&:waiting?)
end
Expand Down
2 changes: 2 additions & 0 deletions app/services/try_user_transition_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ def self.call(user)
when 'completed'
TryUserTransitionFromCompletedService.call(user)
end

user.check_flagged_state
end
end
53 changes: 53 additions & 0 deletions app/views/management/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<table>
<thead>
<tr>
<th>UID</th>
<th>Username</th>
<th>Flagged At</th>
<th>Banned?</th>
<th>Banned At</th>
<th>Notes</th>
<th></th>
</tr>
</thead>
<tbody>
<% @flagged_users.each do |user| %>
<tr>
<td><%= user.uid %></td>
<td><%= user.name %></td>
<td><%= user.system_flagged_at %></td>
<td><%= user.moderator_banned %></td>
<td><%= user.moderator_banned_at %></td>
<td><%= user.moderator_notes %></td>
<td><%# Button to manage user %></td>
</tr>
<% end %>
</tbody>
</table>

<table>
<thead>
<tr>
<th>UID</th>
<th>Username</th>
<th>Banned At</th>
<th>Flagged?</th>
<th>Flagged At</th>
<th>Notes</th>
<th></th>
</tr>
</thead>
<tbody>
<% @banned_users.each do |user| %>
<tr>
<td><%= user.uid %></td>
<td><%= user.name %></td>
<td><%= user.moderator_banned_at %></td>
<td><%= user.system_flagged %></td>
<td><%= user.system_flagged_at %></td>
<td><%= user.moderator_notes %></td>
<td><%# Button to manage user %></td>
</tr>
<% end %>
</tbody>
</table>
35 changes: 35 additions & 0 deletions app/views/management/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<section class="section reg-content">
<div>
<h1 class="title is-1">About you</h1>
<p>
Please select which email address you'd like
to use for Hacktoberfest:
</p>

<%= form_for @user, url: management_update_path(@user.uid), method: :patch do |f| %>
<div class="field">
<label class="label">Is moderator?</label>
<div class="control">
<%= f.check_box :is_moderator %>
</div>
</div>

<div class="field">
<label class="label">Moderator notes</label>
<div class="control">
<%= f.text_area :moderator_notes %>
</div>
</div>

<%= f.submit 'Update user', :class => 'button'%>
<% end %>

<% if @user.banned? %>
<%= button_to 'Unban User', management_unban_path(@user.uid), class: 'button',
method: :post %>
<% else %>
<%= button_to 'Ban User', management_ban_path(@user.uid), class: 'button',
method: :post %>
<% end %>
</div>
</section>
45 changes: 28 additions & 17 deletions app/views/users/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,34 @@
</div>
<% end %>

<div class="hacktoberfest-results-box">
<% if @presenter.display_coupon? %>
<%= render partial: 'users/show/display_coupons', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_sticker_gift? %>
<%= render partial: 'users/show/display_sticker_gift', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_waiting_for_prize? %>
<%= render partial: 'users/show/waiting_for_prize', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_thank_you? %>
<%= render partial: 'users/show/thank_you', locals: { user: @presenter.user } %>
<% end %>
</div>
<div class="container">
<%= render partial: 'users/show/timeline', locals: { user: @presenter.user, scoring_pull_requests: @presenter.scoring_pull_requests, non_scoring_pull_requests: @presenter.non_scoring_pull_requests, show_timer: @presenter.show_timer?, show_congratulations: @presenter.show_congratulations? } %>
</div>
<% if @presenter.show_banned_message? %>
<div class="container pre-launch-container">
<h4 class="title is-4">
Unfortunately, too many of your pull requests have been marked as
spam, making you ineligible to participate in Hacktoberfest this
year. If you think this is invalid, we encourage you to
<%= link_to "contact support", "mailto:hacktoberfest@digialocean.com" %>.
</h4>
</div>
<% else %>
<div class="hacktoberfest-results-box">
<% if @presenter.display_coupon? %>
<%= render partial: 'users/show/display_coupons', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_sticker_gift? %>
<%= render partial: 'users/show/display_sticker_gift', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_waiting_for_prize? %>
<%= render partial: 'users/show/waiting_for_prize', locals: { code: @presenter.code } %>
<% end %>
<% if @presenter.display_thank_you? %>
<%= render partial: 'users/show/thank_you', locals: { user: @presenter.user } %>
<% end %>
</div>
<div class="container">
<%= render partial: 'users/show/timeline', locals: { user: @presenter.user, scoring_pull_requests: @presenter.scoring_pull_requests, non_scoring_pull_requests: @presenter.non_scoring_pull_requests, show_timer: @presenter.show_timer?, show_congratulations: @presenter.show_congratulations? } %>
</div>
<% end %>
</div>

<div class="main-content-wrapper">
Expand Down
7 changes: 7 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@
get '/profile/edit', to: 'users#edit'
patch '/profile/edit', to: 'users#update'

# Management
get '/management', to: 'management#index', as: :management
get '/management/:user_uid', to: 'management#show', as: :management_user
patch '/management/:user_uid', to: 'management#update', as: :management_update
post '/management/:user_uid/ban', to: 'management#ban', as: :management_ban
post '/management/:user_uid/unban', to: 'management#unban', as: :management_unban

# Pages
get '/details', to: 'pages#details'
get '/events', to: 'pages#events'
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20200827143754_allow_users_to_be_flagged_and_banned.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class AllowUsersToBeFlaggedAndBanned < ActiveRecord::Migration[5.2]
def change
add_column :users, :is_moderator, :boolean, :default => false
add_column :users, :system_flagged, :boolean, :default => false
add_column :users, :system_flagged_at, :timestamp, :default => nil
add_column :users, :moderator_banned, :boolean, :default => false
add_column :users, :moderator_banned_at, :timestamp, :default => nil
add_column :users, :moderator_notes, :text, :default => nil
end
end
6 changes: 6 additions & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,12 @@
t.boolean "dev_marketing_emails", default: false
t.string "category", default: "participant"
t.string "country"
t.boolean "is_moderator", default: false
t.boolean "system_flagged", default: false
t.datetime "system_flagged_at"
t.boolean "moderator_banned", default: false
t.datetime "moderator_banned_at"
t.text "moderator_notes"
end

end
Loading