| Class | User |
| In: |
app/models/user.rb
|
| Parent: | ActiveRecord::Base |
We always assume the following fields exists:
If there are added columns, add the default values to default_values
| STUDENT | = | 'Student' | role constants | |
| ADMIN | = | 'Admin' | ||
| TA | = | 'Ta' | ||
| AUTHENTICATE_SUCCESS | = | 0 | Authentication constants to be used as return values see self.authenticated? and main_controller for details | |
| AUTHENTICATE_NO_SUCH_USER | = | 1 | ||
| AUTHENTICATE_BAD_PASSWORD | = | 2 | ||
| AUTHENTICATE_ERROR | = | 3 | ||
| AUTHENTICATE_BAD_CHAR | = | 4 | ||
| AUTHENTICATE_BAD_PLATFORM | = | 5 |
# File app/models/user.rb, line 159
159: def self.add_user(user_class, row)
160: # convert each line to a hash with FIELDS as corresponding keys
161: # and create or update a user with the hash values
162: #return nil if values.length < UPLOAD_FIELDS.length
163: user_attributes = {}
164: # Loop through the resulting array as key, value pairs
165:
166: user_class::CSV_UPLOAD_ORDER.zip(row) do |key, val|
167: # append them to the hash that is returned by User.get_default_ta/student_attrs
168: user_attributes[key] = val
169: end
170:
171: # Is there already a Student with this User number?
172: current_user = user_class.find_or_create_by_user_name(user_attributes[:user_name])
173: current_user.attributes = user_attributes
174:
175: if !current_user.save
176: return nil
177: end
178:
179: return current_user
180: end
Authenticates login against its password through a script specified by config VALIDATE_FILE
# File app/models/user.rb, line 46
46: def self.authenticate(login, password)
47: # Do not allow the following characters in usernames/passwords
48: # Right now, this is \n and \0 only, since username and password
49: # are delimited by \n and C programs use \0 to terminate strings
50: not_allowed_regexp = Regexp.new(/[\n\0]+/)
51: if !(not_allowed_regexp.match(login) || not_allowed_regexp.match(password))
52: # Open a pipe and write to stdin of the program specified by config VALIDATE_FILE.
53: # We could read something from the programs stdout, but there is no need
54: # for that at the moment (you would do it by e.g. pipe.readlines)
55:
56: # External validation is supported on *NIX only
57: if RUBY_PLATFORM =~ /(:?mswin|mingw)/ # should match for Windows only
58: return AUTHENTICATE_BAD_PLATFORM
59: end
60:
61: # In general, the external password validation program will return the
62: # following codes (other than 0):
63: # 1 means no such user
64: # 2 means bad password
65: # 3 is used for other error exits
66: pipe = IO.popen( MarkusConfigurator.markus_config_validate_file, "w+" )
67: pipe.puts("#{login}\n#{password}") # write to stdin of markus_config_validate
68: pipe.close
69: m_logger = MarkusLogger.instance
70: case $?.exitstatus
71: when 0
72: m_logger.log(I18n.t("markus_logger.user_login_message", :user_name => login), MarkusLogger::INFO)
73: return AUTHENTICATE_SUCCESS
74: when 1
75: m_logger.log(I18n.t("markus_logger.user_wrong_credentials", :user_name => login), MarkusLogger::ERROR)
76: return AUTHENTICATE_NO_SUCH_USER
77: when 2
78: m_logger.log(I18n.t("markus_logger.user_wrong_credentials", :user_name => login), MarkusLogger::ERROR)
79: return AUTHENTICATE_BAD_PASSWORD
80: else
81: m_logger.log(I18n.t("markus_logger.user_login_error", :user_name => login),MarkusLogger::ERROR)
82: return AUTHENTICATE_ERROR
83: end
84: else
85: m_logger.log(I18n.t("markus_logger.user_login_error", :user_name => login),MarkusLogger::ERROR)
86: return AUTHENTICATE_BAD_CHAR
87: end
88: end
Verifies if user is allowed to enter MarkUs Returns user object representing the user with the given login.
# File app/models/user.rb, line 39
39: def self.authorize(login)
40: # fetch login in database to see if it is registered.
41: find_by_user_name(login)
42: end
Classlist parsing ———————————————————
# File app/models/user.rb, line 122
122: def self.generate_csv_list(user_list)
123: file_out = FasterCSV.generate do |csv|
124: user_list.each do |user|
125: # csv format is user_name,last_name,first_name
126: user_array = [user.user_name,user.last_name,user.first_name]
127: csv << user_array
128: end
129: end
130: return file_out
131: end
Convenience method which returns a configuration Hash for the repository lib
# File app/models/user.rb, line 184
184: def self.repo_config
185: # create config
186: conf = Hash.new
187: conf["IS_REPOSITORY_ADMIN"] = MarkusConfigurator.markus_config_repository_admin?
188: conf["REPOSITORY_PERMISSION_FILE"] = MarkusConfigurator.markus_config_repository_permission_file
189: return conf
190: end
# File app/models/user.rb, line 133
133: def self.upload_user_list(user_class, user_list)
134: num_update = 0
135: result = {}
136: result[:invalid_lines] = [] # store lines that were not processed
137: # read each line of the file and update classlist
138: User.transaction do
139: processed_users = []
140: FasterCSV.parse(user_list, :skip_blanks => true, :row_sep => :auto) do |row|
141: # don't know how to fetch line so we concat given array
142: next if FasterCSV.generate_line(row).strip.empty?
143: if processed_users.include?(row[0])
144: result[:invalid_lines] = I18n.t('csv_upload_user_duplicate', {:user_name => row[0]})
145: else
146: if User.add_user(user_class, row).nil?
147: result[:invalid_lines] << row.join(",")
148: else
149: num_update += 1
150: processed_users.push(row[0])
151: end
152: end
153: end # end prase
154: end
155: result[:upload_notice] = "#{num_update} user(s) added/updated."
156: return result
157: end
TODO: make these proper associations. They work fine for now but
they'll be slow in production
# File app/models/user.rb, line 93
93: def active_groupings
94: self.groupings.find(:all, :conditions => ["memberships.membership_status != :u", { :u => StudentMembership::STATUSES[:rejected]}])
95: end
Helper methods ——————————————————
# File app/models/user.rb, line 99
99: def admin?
100: self.class == Admin
101: end
Resets the api key. Usually triggered, if the old md5 hash has gotten into the wrong hands.
# File app/models/user.rb, line 216
216: def reset_api_key
217: key = generate_api_key
218: md5 = Digest::MD5.new
219: md5.update(key)
220: # base64 encode md5 hash
221: self.api_key = Base64.encode64(md5.to_s).strip
222: return self.save
223: end
Set API key for user model. The key is a SHA2 512 bit long digest, which is in turn MD5 digested and Base64 encoded so that it doesn‘t include bad HTTP characters.
TODO: If we end up using this heavily we should probably let this token expire every X days/hours/weeks. When it does, a new token should be automatically generated.
# File app/models/user.rb, line 201
201: def set_api_key
202: if self.api_key.nil?
203: key = generate_api_key
204: md5 = Digest::MD5.new
205: md5.update(key)
206: # base64 encode md5 hash
207: self.api_key = Base64.encode64(md5.to_s).strip
208: return self.save
209: else
210: return true
211: end
212: end
Submission helper methods ————————————————-
# File app/models/user.rb, line 113
113: def submission_for(aid)
114: grouping = grouping_for(aid)
115: if grouping.nil?
116: return nil
117: end
118: return grouping.current_submission_used
119: end