forked from buidl-studio/gitcoin-passport-discourse-plugin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
plugin.rb
198 lines (161 loc) · 7.79 KB
/
plugin.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
# frozen_string_literal: true
# name: discourse-gitcoin-passport
# about: A discourse plugin to enable users to manage forum access using Gitcoin Passport
# version: 0.0.1
# authors: Buidl Studio
# url: https://passport.gitcoin.co/
# required_version: 2.7.0
require 'ostruct'
enabled_site_setting :gitcoin_passport_enabled
register_asset "stylesheets/create-account-feedback-message.scss"
register_asset "stylesheets/passport-score-value.scss"
require_relative "app/validators/ethaddress_validator.rb"
require_relative "app/validators/date_validator.rb"
require_relative "app/validators/ethereum_node_validator.rb"
after_initialize do
module ::DiscourseGitcoinPassport
PLUGIN_NAME = "discourse-gitcoin-passport"
class Engine < ::Rails::Engine
engine_name PLUGIN_NAME
isolate_namespace DiscourseGitcoinPassport
end
class Error < StandardError
end
end
require_relative "app/controllers/passport_controller.rb"
require_relative "lib/gitcoin_passport_module/passport.rb"
require_relative "lib/gitcoin_passport_module/access_without_passport.rb"
require_relative "lib/ens/resolver.rb"
require_relative "lib/ens/coin_type.rb"
require_relative "app/models/user_passport_score.rb"
require_relative "app/models/category_passport_score.rb"
DiscourseGitcoinPassport::Engine.routes.draw do
put "/saveUserScore" => "passport#user_level_gating_score"
put "/saveCategoryScore" => "passport#category_level_gating_score"
put "/refreshPassportScore" => "passport#refresh_score"
end
Discourse::Application.routes.append { mount ::DiscourseGitcoinPassport::Engine, at: "/passport" }
reloadable_patch do |plugin|
User.class_eval { has_many :user_passport_scores, dependent: :destroy }
Category.class_eval { has_many :category_passport_scores, dependent: :destroy }
UsersController.class_eval do
alias_method :existing_create, :create
def create
if SiteSetting.gitcoin_passport_enabled &&
SiteSetting.gitcoin_passport_scorer_id &&
SiteSetting.gitcoin_passport_forum_level_score_to_create_account &&
SiteSetting.gitcoin_passport_forum_level_score_to_create_account.to_f > 0
sesh_hash = session.to_hash
Rails.logger.info("Session hash of new session created: #{sesh_hash.inspect}")
provider = sesh_hash.dig('authentication', 'extra_data', 'provider') # expecting siwe
uid = sesh_hash.dig('authentication', 'extra_data', 'uid') # expecting ethereum address
if (provider != 'siwe' || uid.nil?)
Rails.logger.info("User #{params[:username]} does not have an ethereum address associated with their account")
return fail_with("gitcoin_passport.create_account_wallet_not_connected")
end
score = DiscourseGitcoinPassport::Passport.score(uid, SiteSetting.gitcoin_passport_scorer_id)
required_score_to_create_account = SiteSetting.gitcoin_passport_forum_level_score_to_create_account.to_f
if score.to_i < required_score_to_create_account
message = I18n.t("gitcoin_passport.create_account_minimum_score_not_satisfied", score: score, required_score: required_score_to_create_account)
render json: { success: false, message: message }
return
end
end
existing_create
end
end
SiweAuthenticator.class_eval do
def after_authenticate(auth_token, existing_account: nil)
association = UserAssociatedAccount.where(provider_name: auth_token[:provider], provider_uid: auth_token[:uid]).first
# If the user is already associated with an account, refresh the score and save it in the user table, this is mainly done
# for performance reasons so that we don't have to query the passport api every time we need to check the score
if association and association.user_id
user = User.where(id: association.user_id).first
score = DiscourseGitcoinPassport::Passport.refresh_passport_score(user) || 0
Rails.logger.info("User #{user.username} has a passport score of #{score}. Saving it ...")
user.update(passport_score: score, passport_score_last_update: Time.now)
end
super
end
def after_create_account(user, auth)
if SiteSetting.gitcoin_passport_enabled
user_hash = user.attributes
user_hash["associated_accounts"] = [{
name: "siwe",
description: auth[:extra_data][:uid]
}]
user_ostruct = OpenStruct.new(user_hash)
Rails.logger.info("Found user #{user_ostruct.username} with id #{user_ostruct.id} and ethereum address #{auth[:extra_data][:uid]}. Refreshing passport score ...")
score = DiscourseGitcoinPassport::Passport.refresh_passport_score(user_ostruct) || 0
Rails.logger.info("User #{user_ostruct.username} has a passport score of #{score}. Saving it ...")
user.update(passport_score: score, passport_score_last_update: Time.now)
end
super
end
end
TopicGuardian.class_eval do
alias_method :existing_can_create_post_on_topic?, :can_create_post_on_topic?
alias_method :existing_can_create_topic_on_category?, :can_create_topic_on_category?
def can_create_post_on_topic?(topic)
if DiscourseGitcoinPassport::AccessWithoutPassport.expired?
category = Category.where(id: topic.category_id).first
if !DiscourseGitcoinPassport::Passport.has_minimimum_required_score?(@user, category, UserAction.types[:reply])
Rails.logger.info("User #{@user[:username]} does not have the minimum required score to post on topic #{topic[:id]} in category #{category[:id]}")
return false
end
end
existing_can_create_post_on_topic?(topic)
end
def can_create_topic_on_category?(category)
if DiscourseGitcoinPassport::AccessWithoutPassport.expired?
if !DiscourseGitcoinPassport::Passport.has_minimimum_required_score?(@user, category, UserAction.types[:new_topic])
Rails.logger.info("User #{@user[:username]} does not have the minimum required score to create a topic on category #{category[:id]}")
return false
end
end
existing_can_create_topic_on_category?(category)
end
end
end
add_to_serializer(
:current_user,
:ethaddress,
) do
siwe_account = object.associated_accounts.find { |account| account[:name] == "siwe" }
siwe_account[:description] if siwe_account
end
add_to_serializer(
:current_user,
:passport_score,
) do
object.passport_score
end
add_to_serializer(
:admin_detailed_user,
:min_score_to_post,
) do
UserPassportScore
.where(user_id: object.id, user_action_type: UserAction.types[:reply]).exists? ? UserPassportScore.where(user_id: object.id, user_action_type: UserAction.types[:reply]).first.required_score : 0
end
add_to_serializer(
:admin_detailed_user,
:min_score_to_create_topic,
) do
UserPassportScore
.where(user_id: object.id, user_action_type: UserAction.types[:new_topic]).exists? ? UserPassportScore.where(user_id: object.id, user_action_type: UserAction.types[:new_topic]).first.required_score : 0
end
add_to_serializer(
:category,
:min_score_to_post,
) do
CategoryPassportScore
.where(category_id: object.id, user_action_type: UserAction.types[:reply]).exists? ? CategoryPassportScore.where(category_id: object.id, user_action_type: UserAction.types[:reply]).first.required_score : 0
end
add_to_serializer(
:category,
:min_score_to_create_topic,
) do
CategoryPassportScore
.where(category_id: object.id, user_action_type: UserAction.types[:new_topic]).exists? ? CategoryPassportScore.where(category_id: object.id, user_action_type: UserAction.types[:new_topic]).first.required_score : 0
end
end