mumuki-domain 8.6.1 → 9.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/application_record.rb +20 -0
  3. data/app/models/assignment.rb +2 -2
  4. data/app/models/certificate.rb +29 -0
  5. data/app/models/certificate_program.rb +42 -0
  6. data/app/models/concerns/with_assignments.rb +2 -3
  7. data/app/models/concerns/with_assignments_batch.rb +2 -2
  8. data/app/models/concerns/with_generated_code.rb +19 -0
  9. data/app/models/concerns/with_notifications.rb +1 -1
  10. data/app/models/course.rb +26 -2
  11. data/app/models/discussion.rb +1 -1
  12. data/app/models/exercise.rb +13 -0
  13. data/app/models/guide.rb +1 -10
  14. data/app/models/invitation.rb +7 -11
  15. data/app/models/message.rb +22 -2
  16. data/app/models/organization.rb +1 -1
  17. data/app/models/topic.rb +7 -12
  18. data/app/models/user.rb +28 -1
  19. data/db/migrate/20210119174504_create_certificate_programs.rb +13 -0
  20. data/db/migrate/20210119174835_create_certificates.rb +13 -0
  21. data/db/migrate/20210301210530_add_period_start_and_end_to_course.rb +7 -0
  22. data/db/migrate/20210302181654_add_faqs_to_organizations.rb +5 -0
  23. data/db/migrate/20210308145910_add_approved_by_and_at_to_message.rb +6 -0
  24. data/db/migrate/20210310195602_add_delete_account_token_to_user.rb +6 -0
  25. data/lib/mumuki/domain/factories.rb +2 -0
  26. data/lib/mumuki/domain/factories/certificate_factory.rb +8 -0
  27. data/lib/mumuki/domain/factories/certificate_program_factory.rb +7 -0
  28. data/lib/mumuki/domain/factories/organization_factory.rb +2 -1
  29. data/lib/mumuki/domain/helpers/course.rb +1 -1
  30. data/lib/mumuki/domain/organization/settings.rb +2 -2
  31. data/lib/mumuki/domain/version.rb +1 -1
  32. metadata +15 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 339d512e2040015c6556f9671fd00281edf9b651a5dc9db8f860d7607989cd65
4
- data.tar.gz: a03fe1fe26593986af16d89c1df6cc6e9b8f21c3e9e240de41f884482e75c6d7
3
+ metadata.gz: 46425c74cf597dd17603273a455f7a5956c2f0b80926f81e739f45de0bd4e17e
4
+ data.tar.gz: 9241fe5525d3c387e726fda5037044c96564d77c802ec4af9e01de086648018e
5
5
  SHA512:
6
- metadata.gz: ea2475a456f0558a61e798d27e88921a7a69b134dc38431c1244033d778dbc1b91ce4a974acaa6abbf77cceed03134430cb378f2e4d4561f39d297a7040a9745
7
- data.tar.gz: 1321dbd879300fb21e87ef044bae0a7bcbca62ff9fc27cf55bfac1e02cc122273952add367a94381a54e1b730e68549659e5abb9762795071e8c7fa89d6a3699
6
+ metadata.gz: f7ff8c266a27514fac9fe776572efa0ec5d742627bda381b42218364853d75bd51c22aa7aae86be0fb0c8692e9b9b43209e96bc8ac6015cebacce0f3cdb869e7
7
+ data.tar.gz: 4ba53f6362fcbbbb38e9be6fc19e8a90561cfb02e6a0cc2ba82e597ca5cae8fc06d768f2e0ec7ef8255366d241f5558b1a0f2409b34bedc074466792d78f27fa
@@ -87,6 +87,22 @@ class ApplicationRecord < ActiveRecord::Base
87
87
  end
88
88
  end
89
89
 
90
+ def self.with_temporary_token(field_name, duration = 2.hours)
91
+ class_eval do
92
+ token_attribute = field_name
93
+ token_date_attribute = "#{field_name}_expiration_date"
94
+
95
+ define_method("generate_#{field_name}!") do
96
+ update!(token_attribute => self.class.generate_secure_token, token_date_attribute => duration.from_now)
97
+ end
98
+
99
+ define_method("#{field_name}_matches?") do |token|
100
+ actual_token = attribute(token_attribute)
101
+ actual_token.present? && token == actual_token && attribute(token_date_attribute)&.future?
102
+ end
103
+ end
104
+ end
105
+
90
106
  def self.numbered(*associations)
91
107
  class_eval do
92
108
  associations.each do |it|
@@ -140,4 +156,8 @@ class ApplicationRecord < ActiveRecord::Base
140
156
  def raise_foreign_key_error!
141
157
  raise ActiveRecord::InvalidForeignKey.new "#{model_name} is still referenced"
142
158
  end
159
+
160
+ def self.generate_secure_token
161
+ SecureRandom.base58(24)
162
+ end
143
163
  end
@@ -275,11 +275,11 @@ class Assignment < Progress
275
275
 
276
276
  def update_submissions_count!
277
277
  self.class.connection.execute(
278
- "update public.exercises
278
+ "update exercises
279
279
  set submissions_count = submissions_count + 1
280
280
  where id = #{exercise.id}")
281
281
  self.class.connection.execute(
282
- "update public.assignments
282
+ "update assignments
283
283
  set submissions_count = submissions_count + 1
284
284
  where id = #{id}")
285
285
  exercise.reload
@@ -0,0 +1,29 @@
1
+ class Certificate < ApplicationRecord
2
+ include WithGeneratedCode
3
+
4
+ belongs_to :user
5
+ belongs_to :certificate_program
6
+
7
+ has_one :organization, through: :certificate_program
8
+
9
+ delegate :title, :description, :template_html_erb, :background_image_url, to: :certificate_program
10
+
11
+ def self.code_size
12
+ 12
13
+ end
14
+
15
+ def filename
16
+ "#{title.parameterize.underscore}.pdf"
17
+ end
18
+
19
+ def template_locals
20
+ { user: user,
21
+ certificate_program: certificate_program,
22
+ organization: organization,
23
+ certificate: self }
24
+ end
25
+
26
+ def for_user?(user)
27
+ self.user == user
28
+ end
29
+ end
@@ -0,0 +1,42 @@
1
+ class CertificateProgram < ApplicationRecord
2
+ belongs_to :organization
3
+ has_many :certificates
4
+
5
+ def friendly
6
+ title
7
+ end
8
+
9
+ def template_html_erb
10
+ self[:template_html_erb] ||= <<HTML
11
+ <style>
12
+ .qr-code {
13
+ bottom: 5px;
14
+ right: 5px;
15
+ height: 15mm;
16
+ width: 15mm;
17
+ }
18
+ .name {
19
+ position: absolute;
20
+ width: 100%;
21
+ top: 380px;
22
+ text-align: center;
23
+ }
24
+ </style>
25
+ <!-- You can use interpolations like --
26
+ <%#= certificate.start_date %>
27
+ <%#= certificate.end_date %>
28
+ <%#= user.formal_first_name %>
29
+ <%#= user.formal_last_name %>
30
+ <%#= user.formal_full_name %>
31
+ <%#= certificate_program.title %>
32
+ <%#= certificate_program.description %>
33
+ <%#= organization.name %>
34
+ <%#= organization.display_name %>
35
+ -- -->
36
+ <section class="name">
37
+ <h1><%= user.formal_full_name %></h1>
38
+ </section>
39
+ HTML
40
+ end
41
+
42
+ end
@@ -19,9 +19,8 @@ module WithAssignments
19
19
  end
20
20
 
21
21
  # TODO: When the organization is used in this one, please change guide.pending_exercises
22
- # TODO: Please do the same on WithAssignmentsBatch
23
- def find_assignment_for(user, _organization)
24
- assignments.find_by(submitter: user)
22
+ def find_assignment_for(user, organization)
23
+ assignments.find_by(submitter: user, organization: organization)
25
24
  end
26
25
 
27
26
  def status_for(user)
@@ -4,13 +4,13 @@
4
4
  module WithAssignmentsBatch
5
5
  extend ActiveSupport::Concern
6
6
 
7
- def find_assignments_for(user, _organization = Organization.current, &block)
7
+ def find_assignments_for(user, organization = Organization.current, &block)
8
8
  block = block_given? ? block : lambda { |it, _e| it }
9
9
 
10
10
  return exercises.map { |it| block.call nil, it } unless user
11
11
 
12
12
  pairs = exercises.map { |it| [it.id, [nil, it]] }.to_h
13
- Assignment.where(submitter: user, exercise: exercises).each do |it|
13
+ Assignment.where(submitter: user, organization: organization, exercise: exercises).each do |it|
14
14
  pairs[it.exercise_id][0] = it
15
15
  end
16
16
 
@@ -0,0 +1,19 @@
1
+ module WithGeneratedCode
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ validates_uniqueness_of :code
6
+
7
+ defaults do
8
+ self.code ||= self.class.generate_code
9
+ end
10
+
11
+ required :code_size
12
+ end
13
+
14
+ class_methods do
15
+ def generate_code
16
+ SecureRandom.urlsafe_base64 code_size
17
+ end
18
+ end
19
+ end
@@ -2,7 +2,7 @@ module WithNotifications
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  def unread_messages
5
- messages.where read: false
5
+ messages_in_organization.where read: false
6
6
  end
7
7
 
8
8
  def unread_notifications
data/app/models/course.rb CHANGED
@@ -3,7 +3,7 @@ class Course < ApplicationRecord
3
3
  include Mumuki::Domain::Helpers::Course
4
4
  include Mumuki::Domain::Area
5
5
 
6
- validates_presence_of :slug, :shifts, :code, :days, :period, :description, :organization_id
6
+ validates_presence_of :slug, :period, :code, :description, :organization_id
7
7
  validates_uniqueness_of :slug
8
8
  belongs_to :organization
9
9
 
@@ -11,7 +11,7 @@ class Course < ApplicationRecord
11
11
 
12
12
  alias_attribute :name, :code
13
13
 
14
- resource_fields :slug, :shifts, :code, :days, :period, :description
14
+ resource_fields :slug, :shifts, :code, :days, :period, :description, :period_start, :period_end
15
15
 
16
16
  def current_invitation
17
17
  invitations.where('expiration_date > ?', Time.now).first
@@ -35,6 +35,30 @@ class Course < ApplicationRecord
35
35
  end
36
36
  end
37
37
 
38
+ def ended?
39
+ period_end.present? && period_end.past?
40
+ end
41
+
42
+ def started?
43
+ period_start.present? && period_start.past?
44
+ end
45
+
46
+ def infer_period_range!
47
+ return if period_start || period_end
48
+
49
+ period =~ /^(\d{4})?/
50
+ year = $1.to_i
51
+
52
+ return nil unless year.between? 2014, (DateTime.now.year + 1)
53
+
54
+ self.period_start = DateTime.new(year).beginning_of_year
55
+ self.period_end = DateTime.new(year).end_of_year
56
+ end
57
+
58
+ def canonical_code
59
+ "#{period}-#{code}".downcase
60
+ end
61
+
38
62
  def closed?
39
63
  current_invitation.blank? || current_invitation.expired?
40
64
  end
@@ -167,7 +167,7 @@ class Discussion < ApplicationRecord
167
167
  end
168
168
 
169
169
  def being_accessed_by_moderator?
170
- last_moderator_access_at.present? && last_moderator_access_at > Time.now - MODERATOR_REVIEW_AVERAGE_TIME
170
+ last_moderator_access_at.present? && (last_moderator_access_at + MODERATOR_REVIEW_AVERAGE_TIME).future?
171
171
  end
172
172
 
173
173
  def last_moderator_access_visible_for?(user)
@@ -267,4 +267,17 @@ class Exercise < ApplicationRecord
267
267
  def self.default_layout
268
268
  layouts.keys[0]
269
269
  end
270
+
271
+ def self.with_pending_assignments_for(user, relation)
272
+ relation.
273
+ joins("left join assignments assignments
274
+ on assignments.exercise_id = exercises.id
275
+ and assignments.submitter_id = #{user.id}
276
+ and assignments.organization_id = #{Organization.current.id}
277
+ and assignments.submission_status in (
278
+ #{Mumuki::Domain::Status::Submission::Passed.to_i},
279
+ #{Mumuki::Domain::Status::Submission::ManualEvaluationPending.to_i}
280
+ )").
281
+ where('assignments.id is null')
282
+ end
270
283
  end
data/app/models/guide.rb CHANGED
@@ -50,17 +50,8 @@ class Guide < Content
50
50
  end
51
51
  end
52
52
 
53
- # TODO: Make use of pending_siblings logic
54
53
  def pending_exercises(user)
55
- exercises.
56
- joins("left join public.assignments assignments
57
- on assignments.exercise_id = exercises.id
58
- and assignments.submitter_id = #{user.id}
59
- and assignments.submission_status in (
60
- #{Mumuki::Domain::Status::Submission::Passed.to_i},
61
- #{Mumuki::Domain::Status::Submission::ManualEvaluationPending.to_i}
62
- )").
63
- where('assignments.id is null')
54
+ Exercise.with_pending_assignments_for(user, exercises)
64
55
  end
65
56
 
66
57
  def first_exercise
@@ -1,14 +1,10 @@
1
1
  class Invitation < ApplicationRecord
2
- include Mumuki::Domain::Syncable
2
+ include Mumuki::Domain::Syncable,
3
+ WithGeneratedCode
3
4
 
4
5
  belongs_to :course
5
6
 
6
7
  validate :ensure_not_expired, on: :create
7
- validates_uniqueness_of :code
8
-
9
- defaults do
10
- self.code ||= self.class.generate_code
11
- end
12
8
 
13
9
  def ensure_not_expired
14
10
  errors.add(:base, :invitation_expired) if expired?
@@ -43,7 +39,7 @@ class Invitation < ApplicationRecord
43
39
  end
44
40
 
45
41
  def expired?
46
- Time.now > expiration_date
42
+ expiration_date.past?
47
43
  end
48
44
 
49
45
  def unexpired
@@ -51,12 +47,12 @@ class Invitation < ApplicationRecord
51
47
  self
52
48
  end
53
49
 
54
- def self.generate_code
55
- SecureRandom.urlsafe_base64 4
56
- end
57
-
58
50
  private
59
51
 
52
+ def self.code_size
53
+ 4
54
+ end
55
+
60
56
  def course_name
61
57
  course.name
62
58
  end
@@ -2,6 +2,8 @@ class Message < ApplicationRecord
2
2
 
3
3
  belongs_to :discussion, optional: true
4
4
  belongs_to :assignment, foreign_key: :submission_id, primary_key: :submission_id, optional: true
5
+ belongs_to :approved_by, class_name: 'User', optional: true
6
+
5
7
  has_one :exercise, through: :assignment
6
8
 
7
9
  validates_presence_of :content, :sender
@@ -50,14 +52,22 @@ class Message < ApplicationRecord
50
52
  update! read: true
51
53
  end
52
54
 
53
- def toggle_approved!
54
- toggle! :approved
55
+ def toggle_approved!(user)
56
+ if approved?
57
+ disapprove!
58
+ else
59
+ approve!(user)
60
+ end
55
61
  end
56
62
 
57
63
  def toggle_not_actually_a_question!
58
64
  toggle! :not_actually_a_question
59
65
  end
60
66
 
67
+ def approved?
68
+ approved_at?
69
+ end
70
+
61
71
  def validated?
62
72
  approved? || from_moderator?
63
73
  end
@@ -93,4 +103,14 @@ class Message < ApplicationRecord
93
103
  Assignment.find_by(submission_id: message_data.delete('submission_id'))&.receive_answer! message_data
94
104
  end
95
105
  end
106
+
107
+ private
108
+
109
+ def approve!(user)
110
+ update! approved: true, approved_at: Time.now, approved_by: user
111
+ end
112
+
113
+ def disapprove!
114
+ update! approved: false, approved_at: nil, approved_by: nil
115
+ end
96
116
  end
@@ -11,7 +11,7 @@ class Organization < ApplicationRecord
11
11
  serialize :settings, Mumuki::Domain::Organization::Settings
12
12
  serialize :theme, Mumuki::Domain::Organization::Theme
13
13
 
14
- markdown_on :description, :display_description, :page_description
14
+ markdown_on :description, :display_description, :page_description, :faqs
15
15
  teaser_on :display_description
16
16
 
17
17
  validate :ensure_consistent_public_login
data/app/models/topic.rb CHANGED
@@ -50,18 +50,13 @@ class Topic < Content
50
50
  end
51
51
 
52
52
  def pending_lessons(user)
53
- lessons
54
- .includes(:guide)
55
- .references(:guide)
56
- .joins('left join exercises exercises on exercises.guide_id = guides.id')
57
- .joins("left join assignments assignments
58
- on assignments.exercise_id = exercises.id
59
- and assignments.submitter_id = #{user.id}
60
- and assignments.submission_status in (
61
- #{Mumuki::Domain::Status::Submission::Passed.to_i},
62
- #{Mumuki::Domain::Status::Submission::ManualEvaluationPending.to_i}
63
- )")
64
- .where('assignments.id is null')
53
+ Exercise
54
+ .with_pending_assignments_for(
55
+ user,
56
+ lessons
57
+ .includes(:guide)
58
+ .references(:guide)
59
+ .joins('left join exercises exercises on exercises.guide_id = guides.id'))
65
60
  .group('guides.id', 'lessons.number', 'lessons.id')
66
61
  end
67
62
 
data/app/models/user.rb CHANGED
@@ -35,6 +35,8 @@ class User < ApplicationRecord
35
35
 
36
36
  has_many :exams, through: :exam_authorizations
37
37
 
38
+ has_many :certificates
39
+
38
40
  enum gender: %i(female male other unspecified)
39
41
  belongs_to :avatar, polymorphic: true, optional: true
40
42
 
@@ -47,11 +49,16 @@ class User < ApplicationRecord
47
49
  PLACEHOLDER_IMAGE_URL = 'user_shape.png'.freeze
48
50
 
49
51
  resource_fields :uid, :social_id, :email, :permissions, :verified_first_name, :verified_last_name, *profile_fields
52
+ with_temporary_token :delete_account_token
50
53
 
51
54
  def last_lesson
52
55
  last_guide.try(:lesson)
53
56
  end
54
57
 
58
+ def messages_in_organization(organization = Organization.current)
59
+ messages.where('assignments.organization': organization)
60
+ end
61
+
55
62
  def passed_submissions_count_in(organization)
56
63
  assignments.where(top_submission_status: Mumuki::Domain::Status::Submission::Passed.to_i, organization: organization).count
57
64
  end
@@ -217,7 +224,7 @@ class User < ApplicationRecord
217
224
  end
218
225
 
219
226
  def next_exercise_at(guide)
220
- guide.pending_exercises(self).order('public.exercises.number asc').first
227
+ guide.pending_exercises(self).order('exercises.number asc').first
221
228
  end
222
229
 
223
230
  def run_submission!(submission, assignment, evaluation)
@@ -275,6 +282,26 @@ class User < ApplicationRecord
275
282
  end
276
283
  end
277
284
 
285
+ def formal_first_name
286
+ verified_first_name || first_name
287
+ end
288
+
289
+ def formal_last_name
290
+ verified_last_name || last_name
291
+ end
292
+
293
+ def formal_full_name
294
+ "#{formal_first_name} #{formal_last_name}"
295
+ end
296
+
297
+ def certificates_in_organization(organization = Organization.current)
298
+ certificates.where certificate_program: CertificateProgram.where(organization: organization)
299
+ end
300
+
301
+ def certificated_in?(certificate_program)
302
+ certificates.where(certificate_program: certificate_program).exists?
303
+ end
304
+
278
305
  private
279
306
 
280
307
  def welcome_to_new_organizations!
@@ -0,0 +1,13 @@
1
+ class CreateCertificatePrograms < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :certificate_programs do |t|
4
+ t.string :title
5
+ t.string :template_html_erb
6
+ t.text :description
7
+ t.string :background_image_url
8
+ t.references :organization, index: true
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ class CreateCertificates < ActiveRecord::Migration[5.1]
2
+ def change
3
+ create_table :certificates do |t|
4
+ t.references :user, index: true
5
+ t.references :certificate_program, index: true
6
+ t.datetime :start_date
7
+ t.datetime :end_date
8
+ t.string :code
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ class AddPeriodStartAndEndToCourse < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :courses, :period_start, :datetime
4
+ add_column :courses, :period_end, :datetime
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ class AddFAQsToOrganizations < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :organizations, :faqs, :text
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class AddApprovedByAndAtToMessage < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :messages, :approved_at, :datetime
4
+ add_reference :messages, :approved_by, index: true
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddDeleteAccountTokenToUser < ActiveRecord::Migration[5.1]
2
+ def change
3
+ add_column :users, :delete_account_token, :string
4
+ add_column :users, :delete_account_token_expiration_date, :datetime
5
+ end
6
+ end
@@ -2,6 +2,8 @@ require_relative './factories/api_client_factory'
2
2
  require_relative './factories/assignments_factory'
3
3
  require_relative './factories/avatar_factory'
4
4
  require_relative './factories/book_factory'
5
+ require_relative './factories/certificate_factory'
6
+ require_relative './factories/certificate_program_factory'
5
7
  require_relative './factories/chapter_factory'
6
8
  require_relative './factories/complement_factory'
7
9
  require_relative './factories/course_factory'
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :certificate do
3
+ start_date { 1.month.ago }
4
+ end_date { 1.minute.ago }
5
+ user { build :user, first_name: 'Jane', last_name: 'Doe' }
6
+ certificate_program { build :certificate_program }
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :certificate_program do
3
+ title { 'Test' }
4
+ description { 'Certificate program to test' }
5
+ organization { Organization.current }
6
+ end
7
+ end
@@ -29,7 +29,8 @@ FactoryBot.define do
29
29
  book { create(:book, name: 'test', slug: 'mumuki/mumuki-the-book') }
30
30
  end
31
31
 
32
- factory :another_test_organization, parent: :test_organization, traits: [:skip_unique_name_validation] do
32
+ factory :another_test_organization, parent: :test_organization do
33
+ name { 'another-test' }
33
34
  book { create(:book, name: 'another-test', slug: 'mumuki/mumuki-another-book') }
34
35
  end
35
36
 
@@ -8,6 +8,6 @@ module Mumuki::Domain::Helpers::Course
8
8
  ## API Exposure
9
9
 
10
10
  def to_param
11
- slug
11
+ canonical_code
12
12
  end
13
13
  end
@@ -40,10 +40,10 @@ class Mumuki::Domain::Organization::Settings < Mumukit::Platform::Model
40
40
  end
41
41
 
42
42
  def disabled?
43
- disabled_from.present? && disabled_from < Time.now
43
+ disabled_from.present? && disabled_from.past?
44
44
  end
45
45
 
46
46
  def in_preparation?
47
- in_preparation_until.present? && in_preparation_until > Time.now
47
+ in_preparation_until.present? && in_preparation_until.future?
48
48
  end
49
49
  end
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Domain
3
- VERSION = '8.6.1'
3
+ VERSION = '9.0.5'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumuki-domain
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.6.1
4
+ version: 9.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Franco Leonardo Bulgarelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-26 00:00:00.000000000 Z
11
+ date: 2021-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '6.1'
131
+ version: '7.0'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '6.1'
138
+ version: '7.0'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: mumukit-sync
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -249,6 +249,8 @@ files:
249
249
  - app/models/assignment.rb
250
250
  - app/models/avatar.rb
251
251
  - app/models/book.rb
252
+ - app/models/certificate.rb
253
+ - app/models/certificate_program.rb
252
254
  - app/models/chapter.rb
253
255
  - app/models/complement.rb
254
256
  - app/models/concerns/assistable.rb
@@ -280,6 +282,7 @@ files:
280
282
  - app/models/concerns/with_discussions.rb
281
283
  - app/models/concerns/with_editor.rb
282
284
  - app/models/concerns/with_expectations.rb
285
+ - app/models/concerns/with_generated_code.rb
283
286
  - app/models/concerns/with_language.rb
284
287
  - app/models/concerns/with_layout.rb
285
288
  - app/models/concerns/with_locale.rb
@@ -651,7 +654,13 @@ files:
651
654
  - db/migrate/20210118180941_create_exam_authorization_request.rb
652
655
  - db/migrate/20210118194904_create_notification.rb
653
656
  - db/migrate/20210119160440_add_prevent_manual_evaluation_content_to_organizations.rb
657
+ - db/migrate/20210119174504_create_certificate_programs.rb
658
+ - db/migrate/20210119174835_create_certificates.rb
654
659
  - db/migrate/20210119190204_create_exam_registration_exam_join_table.rb
660
+ - db/migrate/20210301210530_add_period_start_and_end_to_course.rb
661
+ - db/migrate/20210302181654_add_faqs_to_organizations.rb
662
+ - db/migrate/20210308145910_add_approved_by_and_at_to_message.rb
663
+ - db/migrate/20210310195602_add_delete_account_token_to_user.rb
655
664
  - lib/mumuki/domain.rb
656
665
  - lib/mumuki/domain/area.rb
657
666
  - lib/mumuki/domain/engine.rb
@@ -680,6 +689,8 @@ files:
680
689
  - lib/mumuki/domain/factories/assignments_factory.rb
681
690
  - lib/mumuki/domain/factories/avatar_factory.rb
682
691
  - lib/mumuki/domain/factories/book_factory.rb
692
+ - lib/mumuki/domain/factories/certificate_factory.rb
693
+ - lib/mumuki/domain/factories/certificate_program_factory.rb
683
694
  - lib/mumuki/domain/factories/chapter_factory.rb
684
695
  - lib/mumuki/domain/factories/complement_factory.rb
685
696
  - lib/mumuki/domain/factories/course_factory.rb