rails-xapi 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +152 -0
  4. data/Rakefile +8 -0
  5. data/app/controllers/rails_xapi/application_controller.rb +7 -0
  6. data/app/helpers/rails_xapi/application_helper.rb +26 -0
  7. data/app/jobs/rails_xapi/application_job.rb +4 -0
  8. data/app/jobs/rails_xapi/create_statement_job.rb +11 -0
  9. data/app/mailers/rails_xapi/application_mailer.rb +6 -0
  10. data/app/models/concerns/serializable.rb +14 -0
  11. data/app/models/rails_xapi/account.rb +27 -0
  12. data/app/models/rails_xapi/activity_definition.rb +143 -0
  13. data/app/models/rails_xapi/actor.rb +227 -0
  14. data/app/models/rails_xapi/application_record.rb +5 -0
  15. data/app/models/rails_xapi/context.rb +163 -0
  16. data/app/models/rails_xapi/context_activity.rb +37 -0
  17. data/app/models/rails_xapi/errors/xapi_error.rb +4 -0
  18. data/app/models/rails_xapi/extension.rb +29 -0
  19. data/app/models/rails_xapi/group_member.rb +21 -0
  20. data/app/models/rails_xapi/interaction_activity.rb +103 -0
  21. data/app/models/rails_xapi/interaction_component.rb +34 -0
  22. data/app/models/rails_xapi/object.rb +150 -0
  23. data/app/models/rails_xapi/result.rb +174 -0
  24. data/app/models/rails_xapi/statement.rb +62 -0
  25. data/app/models/rails_xapi/validators/language_map_validator.rb +64 -0
  26. data/app/models/rails_xapi/verb.rb +260 -0
  27. data/app/services/application_service.rb +16 -0
  28. data/app/services/rails_xapi/query.rb +217 -0
  29. data/app/services/rails_xapi/statement_creator.rb +53 -0
  30. data/app/views/layouts/rails_xapi/application.html.erb +12 -0
  31. data/config/locales/rails_xapi.en.yml +43 -0
  32. data/config/locales/rails_xapi.fr.yml +233 -0
  33. data/config/routes.rb +2 -0
  34. data/db/migrate/20240716144226_create_rails_xapi_actors.rb +16 -0
  35. data/db/migrate/20240716144227_create_rails_xapi_accounts.rb +15 -0
  36. data/db/migrate/20240716144228_create_rails_xapi_verbs.rb +14 -0
  37. data/db/migrate/20240716144229_create_rails_xapi_objects.rb +16 -0
  38. data/db/migrate/20240716144230_create_rails_xapi_activity_definitions.rb +17 -0
  39. data/db/migrate/20240716144231_create_rails_xapi_extensions.rb +13 -0
  40. data/db/migrate/20240716144232_create_rails_xapi_statements.rb +19 -0
  41. data/db/migrate/20240716144233_create_rails_xapi_results.rb +21 -0
  42. data/db/migrate/20240716144234_create_rails_xapi_contexts.rb +23 -0
  43. data/db/migrate/20240716144235_create_rails_xapi_context_activities.rb +16 -0
  44. data/db/migrate/20240716144236_create_rails_xapi_group_members.rb +16 -0
  45. data/db/migrate/20250522093846_create_rails_xapi_interaction_activities.rb +15 -0
  46. data/db/migrate/20250522122830_create_rails_xapi_interaction_component.rb +16 -0
  47. data/lib/rails-xapi/configuration.rb +13 -0
  48. data/lib/rails-xapi/engine.rb +28 -0
  49. data/lib/rails-xapi/version.rb +5 -0
  50. data/lib/rails-xapi.rb +16 -0
  51. data/lib/tasks/auto_annotate_models.rake +62 -0
  52. data/lib/tasks/rails-xapi_tasks.rake +4 -0
  53. metadata +122 -0
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class manages the query interface for verbs.
4
+ class RailsXapi::Query < ApplicationService
5
+ def initialize(query:, args: [])
6
+ @query = query
7
+ @args = args
8
+ end
9
+
10
+ def self.call(query:, args: [])
11
+ new(query: query, args: args).call
12
+ end
13
+
14
+ def call
15
+ if respond_to?(@query, true)
16
+ send(@query, *@args)
17
+ else
18
+ raise RailsXapi::Errors::XapiError,
19
+ I18n.t("rails_xapi.errors.query_not_available")
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # @param id [Integer] The ID of the statement
26
+ # @return [RailsXapi::Statement] The statement record
27
+ def statement(id)
28
+ RailsXapi::Statement.find(id)
29
+ end
30
+
31
+ # Get a hash of all statements concerning the actors emails and object_id.
32
+ #
33
+ # @param object_id [String] The object IRI
34
+ # @param actor_emails [Array<String>] List of actor emails
35
+ # @return [ActiveRecord::Relation] Statements matching criteria
36
+ # @raise [ArgumentError] If no emails provided
37
+ def statements_by_object_and_actors(object_id, actor_emails = [])
38
+ if actor_emails.empty?
39
+ raise ArgumentError, I18n.t("rails_xapi.errors.no_emails_provided")
40
+ end
41
+
42
+ mailto_emails =
43
+ actor_emails.map do |email|
44
+ # Validate each email using RailsXapi::Actor's validation method
45
+ email if RailsXapi::Actor.new(mbox: email).validate_mbox
46
+ end
47
+
48
+ RailsXapi::Statement.where(
49
+ actor: {
50
+ mbox: mailto_emails
51
+ },
52
+ object: {
53
+ id: object_id
54
+ }
55
+ )
56
+ end
57
+
58
+ # Query statements by actor's email
59
+ #
60
+ # @param actor_email [String] Actor email address
61
+ # @return [ActiveRecord::Relation] Statements from this actor
62
+ # @raise [ArgumentError] If email format is invalid
63
+ def actor_by_email(actor_email)
64
+ if actor_email.start_with?("mailto:")
65
+ mbox_value = actor_email
66
+ else
67
+ mbox_value = "mailto:#{actor_email}"
68
+ end
69
+
70
+ # Validate email using RailsXapi::Actor's validation method
71
+ RailsXapi::Actor.new(mbox: mbox_value).validate_mbox
72
+
73
+ RailsXapi::Statement.where(actor: { mbox: mbox_value })
74
+ end
75
+
76
+ # Query statements by actor's mbox
77
+ #
78
+ # @param actor_mbox [String] mbox (e.g., "mailto:user@example.com")
79
+ # @return [ActiveRecord::Relation] Statements for this mbox
80
+ # @raise [ArgumentError] If mbox format is invalid
81
+ def actor_by_mbox(actor_mbox)
82
+ unless actor_mbox.match?(
83
+ /\Amailto:([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/
84
+ )
85
+ raise ArgumentError,
86
+ I18n.t("rails_xapi.errors.malformed_mbox", name: actor_mbox)
87
+ end
88
+
89
+ RailsXapi::Statement.where(actor: { mbox: actor_mbox })
90
+ end
91
+
92
+ # Query statements by actor's account homepage
93
+ #
94
+ # @param actor_account_homepage [String] Account homepage URL
95
+ # @return [ActiveRecord::Relation] Statements for this account
96
+ def actor_by_account_homepage(actor_account_homepage)
97
+ RailsXapi::Statement.where(
98
+ actor: {
99
+ account: {
100
+ home_page: actor_account_homepage
101
+ }
102
+ }
103
+ )
104
+ end
105
+
106
+ # Query statements by actor's openid
107
+ #
108
+ # @param actor_openid [String] The openID
109
+ # @return [ActiveRecord::Relation] Statements for this openID
110
+ def actor_by_openid(actor_openid)
111
+ RailsXapi::Statement.where(actor: { openid: actor_openid })
112
+ end
113
+
114
+ # Query statements by actor's mbox_sha1sum
115
+ #
116
+ # @param actor_mbox_sha1sum [String] SHA1 hash of actor's mbox
117
+ # @return [ActiveRecord::Relation] Statements for this mbox_sha1sum identifier
118
+ def actor_by_mbox_sha1sum(actor_mbox_sha1sum)
119
+ RailsXapi::Statement.where(actor: { mbox_sha1sum: actor_mbox_sha1sum })
120
+ end
121
+
122
+ # Query statements by actor's identifier per month
123
+ #
124
+ # @param actor_identifier [Hash] One key-value pair representing the identifier
125
+ # @param year [Integer] Year (defaults to current)
126
+ # @param month [Integer] Month (defaults to current)
127
+ # @return [ActiveRecord::Relation] Statements in the given month
128
+ # @raise [ArgumentError] If identifier is empty
129
+ def user_statements_per_month(
130
+ actor_identifier = {},
131
+ year = Date.current.year,
132
+ month = Date.current.month
133
+ )
134
+ if actor_identifier.first.empty?
135
+ raise ArgumentError,
136
+ I18n.t(
137
+ "rails_xapi.errors.exactly_one_actor_identifier_must_be_provided"
138
+ )
139
+ end
140
+
141
+ identifier_key, identifier_value = actor_identifier.first
142
+ start_date, end_date =
143
+ self.class.send(:generate_start_date_end_date, year, month)
144
+ RailsXapi::Statement
145
+ .joins(:actor)
146
+ .where(
147
+ actor: {
148
+ identifier_key => identifier_value
149
+ },
150
+ created_at: start_date..end_date
151
+ )
152
+ .group(:id)
153
+ end
154
+
155
+ # Get a list of all unique verb_id values
156
+ #
157
+ # @return [Array<Integer>] Unique verb IDs
158
+ def verb_ids
159
+ RailsXapi::Verb.pluck(:id)
160
+ end
161
+
162
+ # Get a list of all unique verb_display values
163
+ #
164
+ # @return [Array<String>] Unique verb display values
165
+ def verb_displays
166
+ RailsXapi::Verb.pluck(:display)
167
+ end
168
+
169
+ # Get a hash of all unique verbs with verb_id as keys and verb_display as values.
170
+ #
171
+ # @return [Hash{Integer => String}] verb_id => verb_display mapping
172
+ def verbs
173
+ RailsXapi::Verb.pluck(:id, :display)
174
+ end
175
+
176
+ # Take a collection of records and generate a number of records created each day of the given month
177
+ #
178
+ # @param resources [ActiveRecord::Relation] Statement records
179
+ # @param year [Integer] Year for filtering
180
+ # @param month [Integer] Month for filtering
181
+ # @return [ActiveRecord::Relation] Grouped statements by date
182
+ def per_month(resources, year = Date.current.year, month = Date.current.month)
183
+ start_date, end_date =
184
+ self.class.send(:generate_start_date_end_date, year, month)
185
+ resources.where(
186
+ "rails_xapi_statements.created_at": start_date..end_date
187
+ ).group("DATE(rails_xapi_statements.created_at)")
188
+ end
189
+
190
+ # @param data [Array<RailsXapi::Statement>] Statement list
191
+ # @param year [Integer] Year for generating the range
192
+ # @param month [Integer] Month for generating the range
193
+ # @return [Array<Hash>] Array of date/count pairs
194
+ def month_graph_data(
195
+ statements,
196
+ year = Date.current.year,
197
+ month = Date.current.month
198
+ )
199
+ start_date, end_date =
200
+ self.class.send(:generate_start_date_end_date, year, month)
201
+ month_dates = (start_date..end_date).to_a
202
+
203
+ # Create a hash with default value 0 for each date of the current month
204
+ complete_data = month_dates.index_with { 0 }
205
+
206
+ # Transform data to count occurrences for each date
207
+ data_by_date =
208
+ statements
209
+ .group_by { |statement| statement.created_at.to_date }
210
+ .transform_values(&:count)
211
+
212
+ # Merge the existing data with the complete data and format
213
+ complete_data
214
+ .merge(data_by_date)
215
+ .map { |date, count| { date: date.strftime("%Y-%m-%d"), value: count } }
216
+ end
217
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RailsXapi::StatementCreator < ApplicationService
4
+ def initialize(data, actor = {}, opts = {})
5
+ @data = data
6
+ @actor = actor
7
+ @opts = opts
8
+ end
9
+
10
+ def self.create(data, actor = {}, opts = {})
11
+ s = RailsXapi::StatementCreator.new(data, actor, opts).prepare_statement
12
+ # Use a job for asynchronous calls
13
+ return RailsXapi::CreateStatementJob.perform_now(s) if opts[:async]
14
+
15
+ s.save
16
+ { status: 200, statement: s }
17
+ end
18
+
19
+ def prepare_statement
20
+ actor =
21
+ RailsXapi::Actor.build_actor_from_data(@actor.presence || @data[:actor])
22
+
23
+ verb =
24
+ RailsXapi::Verb.find_or_create_by(id: @data[:verb][:id]) do |v|
25
+ v.display = @data[:verb][:display]
26
+ end
27
+
28
+ object = RailsXapi::Object.find_or_create(@data[:object])
29
+ object.update_definition(@data[:object][:definition])
30
+
31
+ result = RailsXapi::Result.new(@data[:result]) if @data[:result].present?
32
+ context = RailsXapi::Context.new(@data[:context]) if @data[
33
+ :context
34
+ ].present?
35
+
36
+ # Create the statement with the associated properties
37
+ statement =
38
+ RailsXapi::Statement.new(
39
+ actor: actor,
40
+ verb: verb,
41
+ object: object,
42
+ result: result,
43
+ context: context,
44
+ timestamp: @data[:timestamp].presence || Time.zone.now
45
+ )
46
+ unless statement.valid?
47
+ raise RailsXapi::Errors::XapiError,
48
+ statement.errors.full_messages.join(", ")
49
+ end
50
+
51
+ statement
52
+ end
53
+ end
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Rails xAPI</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+ <%= stylesheet_link_tag "rails_xapi/application", media: "all" %>
8
+ </head>
9
+ <body>
10
+ <%= yield %>
11
+ </body>
12
+ </html>
@@ -0,0 +1,43 @@
1
+ en:
2
+ rails_xapi:
3
+ errors:
4
+ actor_ifi_must_be_present: "at least one of mbox, mbox_sha1sum, openid, or account must be present"
5
+ attribute_must_be_a_hash: "attribute %{name} must be a hash"
6
+ attribute_must_be_a_valid_language_map: "attribute %{name} must be a language map"
7
+ couldnt_create_the_substatement: "couldn’t create the substatement"
8
+ definition_description_invalid_keys: "invalid keys in definition description: %{values}"
9
+ definition_description_must_be_language_map: "definition description must be a language map"
10
+ exactly_one_actor_identifier_must_be_provided: "exactly one actor identifier must be provided"
11
+ expected_hash: "expected Hash, got %{type}"
12
+ failed_to_create_member: "failed to create member: #{member}"
13
+ invalid_actor: "invalid actor"
14
+ invalid_actor_object_type: "invalid actor's object type: %{name}"
15
+ invalid_json: "invalid JSON"
16
+ invalid_object_object_type: "invalid object's object type: %{name}"
17
+ invalid_object_substatement: "invalid object substatement"
18
+ invalid_score_value: "invalid score value: %{value}"
19
+ invalid_verb_id_url: "verb_id is not a valid URL"
20
+ malformed_account_home_page_url: "malformed account home_page URL: %{url}"
21
+ malformed_email: "malformed email value: %{name}"
22
+ malformed_mbox: "malformed mbox value: %{name}"
23
+ malformed_mbox_sha1sum: "malformed mbox_sha1sum value"
24
+ malformed_openid_uri: "malformed openid URI: %{uri}"
25
+ malformed_uri: "malformed URI: %{uri}"
26
+ missing_actor: "missing actor in the statemement"
27
+ missing_object: "missing object in the statemement: %{name}"
28
+ missing_object_keys: "missing object keys: %{keys}"
29
+ missing_result_keys: "missing result keys: %{keys}"
30
+ missing_values_or_invalid_type: "missing values or invalid type %{values}"
31
+ missing_verb_display: "missing verb display"
32
+ must_be_a_valid_iri: "must be a valid IRI"
33
+ no_emails_provided: "no emails provided"
34
+ query_not_available: "query is not available"
35
+ unexpected_substatement_object_keys: "unexpected substatement object keys: %{keys}"
36
+ value_must_not_be_nil: "value must not be null for the key: %{name}"
37
+ wrong_attribute_type: "wrong attribute type for %{name}: %{value}"
38
+ validations:
39
+ score:
40
+ min: "min must be a decimal number lower than max"
41
+ raw: "raw must be a decimal between min and max inclusive"
42
+ scaled: "scaled must be a decimal number between -1 and 1 inclusive"
43
+ xapi_statement: "xAPI statement"
@@ -0,0 +1,233 @@
1
+ fr:
2
+ rails_xapi:
3
+ errors:
4
+ actor_ifi_must_be_present: "au moins mbox, mbox_sha1sum, openid, ou account doit être présent"
5
+ attribute_must_be_a_hash: "l'attribut %{name} doit être un hash"
6
+ attribute_must_be_a_valid_language_map: "l'attribut %{name} doit être un language map"
7
+ couldnt_create_the_substatement: "la sous-déclaration n'a pas pu être créée"
8
+ definition_description_invalid_keys: "clés incorrectes dans la description de définition : %{values}"
9
+ definition_description_must_be_language_map: "la description de définitionde doit être de type language map"
10
+ exactly_one_actor_identifier_must_be_provided: "exactement un identifiant d'acteur doit être fourni"
11
+ expected_hash: "attendu Hash, fourni %{type}"
12
+ failed_to_create_member: "échec de création d'un membre : #{member}"
13
+ invalid_actor: "acteur invalide"
14
+ invalid_actor_object_type: "type d'objet de l'acteur incorrect : %{name}"
15
+ invalid_json: "JSON non valide"
16
+ invalid_object_object_type: "type d'objet de l'objet incorrect : %{name}"
17
+ invalid_object_substatement: "sous-déclaration d'objet incorrecte"
18
+ invalid_score_value: "valeur de score incorrecte : %{value}"
19
+ invalid_verb_id_url: "verb_id n'est pas une URL valide"
20
+ malformed_account_home_page_url: "home_page URL du compte malformée : %{url}"
21
+ malformed_email: "valeur email malformée : %{name}"
22
+ malformed_mbox: "valeur mbox malformée : %{name}"
23
+ malformed_mbox_sha1sum: "valeur mbox_sha1sum malformée"
24
+ malformed_openid_uri: "valeur openid URI malformée : %{uri}"
25
+ malformed_uri: "URI malformée : %{uri}"
26
+ missing_actor: "acteur manquant dans la déclaration"
27
+ missing_object: "objet manquant dans la déclaration : %{name}"
28
+ missing_object_keys: "clés d'objet manquantes : %{keys}"
29
+ missing_result_keys: "clés de résultat manquantes : %{keys}"
30
+ missing_values_or_invalid_type: "valeurs manquantes ou invalides : %{values}"
31
+ missing_verb_display: "verb display manquant"
32
+ must_be_a_valid_iri: "doit être un IRI valide"
33
+ no_emails_provided: "aucun email fourni"
34
+ query_not_available: "query is not available"
35
+ unexpected_substatement_object_keys: "clés d'objet de sous-déclaration inattendues : %{keys}"
36
+ value_must_not_be_nil: "la valeur ne peut être nulle pour la clé : %{name}"
37
+ wrong_attribute_type: "type d'attribut incorrect pour %{name} : %{value}"
38
+ validations:
39
+ score:
40
+ min: "min doit être un nombre décimal inférieur à max"
41
+ raw: "raw doit être un nombre décimal compris entre min et max inclus"
42
+ scaled: "scaled doit être un nombre décimal compris entre -1 and 1 inclus"
43
+ xapi_statement: "déclaration xAPI"
44
+ xapi:
45
+ activity: "activité"
46
+ "activity definition": "définition d'activité"
47
+ actor: "acteur"
48
+ agent: "agent"
49
+ context: "contexte"
50
+ context_registration: "enregistrement"
51
+ context_parent: "parent"
52
+ context_category: "catégorie"
53
+ context_other: "autre"
54
+ group: "groupe"
55
+ object: "objet"
56
+ result: "résultat"
57
+ statement: "déclaration"
58
+ substatement: "sous-déclaration"
59
+ verb: "verbe"
60
+ verbs:
61
+ "accepted": "accepté"
62
+ "accessed": "accédé"
63
+ "acknowledged": "reconnu"
64
+ "added": "ajouté"
65
+ "agreed": "accepté"
66
+ "appended": "ajouté"
67
+ "approved": "approuvé"
68
+ "archived": "archivé"
69
+ "assigned": "assigné"
70
+ "was at": "était à"
71
+ "attached": "attaché"
72
+ "attended": "assisté"
73
+ "authored": "rédigé"
74
+ "authorized": "autorisé"
75
+ "borrowed": "emprunté"
76
+ "built": "construit"
77
+ "canceled": "annulé"
78
+ "checked in": "enregistré"
79
+ "closed": "fermé"
80
+ "completed": "complété"
81
+ "confirmed": "confirmé"
82
+ "consumed": "consommé"
83
+ "created": "créé"
84
+ "deleted": "supprimé"
85
+ "delivered": "livré"
86
+ "denied": "refusé"
87
+ "disagreed": "désaccordé"
88
+ "disliked": "pas aimé"
89
+ "experienced": "expérimenté"
90
+ "favorited": "mis en favori"
91
+ "found": "trouvé"
92
+ "flagged as inappropriate": "signalé comme inapproprié"
93
+ "followed": "suivi"
94
+ "gave": "donné"
95
+ "hosted": "organisé"
96
+ "ignored": "ignoré"
97
+ "inserted": "inséré"
98
+ "installed": "installé"
99
+ "interacted": "interagi"
100
+ "invited": "invité"
101
+ "joined": "rejoint"
102
+ "left": "quitté"
103
+ "liked": "aimé"
104
+ "listened": "écouté"
105
+ "lost": "perdu"
106
+ "made friend": "fait ami"
107
+ "opened": "ouvert"
108
+ "played": "joué"
109
+ "presented": "présenté"
110
+ "purchased": "acheté"
111
+ "qualified": "qualifié"
112
+ "read": "lu"
113
+ "received": "reçu"
114
+ "rejected": "rejeté"
115
+ "removed": "retiré"
116
+ "removed friend": "retiré ami"
117
+ "replaced": "remplacé"
118
+ "requested": "demandé"
119
+ "requested friend": "demandé en ami"
120
+ "resolved": "résolu"
121
+ "retracted": "rétracté"
122
+ "returned": "retourné"
123
+ "RSVPed maybe": "répondu peut-être"
124
+ "rsvped no": "répondu non"
125
+ "rsvped yes": "répondu oui"
126
+ "satisfied": "satisfait"
127
+ "saved": "enregistré"
128
+ "scheduled": "planifié"
129
+ "searched": "recherché"
130
+ "sold": "vendu"
131
+ "sent": "envoyé"
132
+ "shared": "partagé"
133
+ "sponsored": "sponsorisé"
134
+ "started": "commencé"
135
+ "stopped following": "arrêté de suivre"
136
+ "submitted": "soumis"
137
+ "tagged": "étiqueté"
138
+ "terminated": "terminé"
139
+ "tied": "lié"
140
+ "unfavorited": "retiré des favoris"
141
+ "unliked": "désaimé"
142
+ "unsatisfied": "insatisfait"
143
+ "unsaved": "non enregistré"
144
+ "unshared": "non partagé"
145
+ "updated": "mis à jour"
146
+ "used": "utilisé"
147
+ "watched": "regardé"
148
+ "won": "gagné"
149
+ "answered": "répondu"
150
+ "asked": "demandé"
151
+ "attempted": "tenté"
152
+ "commented": "commenté"
153
+ "exited": "sorti"
154
+ "failed": "échoué"
155
+ "imported": "importé"
156
+ "initialized": "initialisé"
157
+ "launched": "lancé"
158
+ "mastered": "maîtrisé"
159
+ "passed": "réussi"
160
+ "preferred": "préféré"
161
+ "progressed": "progressé"
162
+ "registered": "enregistré"
163
+ "responded": "répondu"
164
+ "resumed": "repris"
165
+ "scored": "noté"
166
+ "suspended": "suspendu"
167
+ "voided": "annulé"
168
+ "edited": "édité"
169
+ "voted down (with reason)": "voté contre (avec raison)"
170
+ "voted up (with reason)": "voté pour (avec raison)"
171
+ "pressed": "pressé"
172
+ "released": "relâché"
173
+ "adjourned": "ajourné"
174
+ "applauded": "applaudi"
175
+ "arranged": "organisé"
176
+ "bookmarked": "mis en favori"
177
+ "called": "appelé"
178
+ "closed sale": "vente conclue"
179
+ "created opportunity": "créé une opportunité"
180
+ "defined": "défini"
181
+ "disabled": "désactivé"
182
+ "discarded": "jeté"
183
+ "downloaded": "téléchargé"
184
+ "earned": "gagné"
185
+ "enabled": "activé"
186
+ "estimated the duration": "estimé la durée"
187
+ "expected": "attendu"
188
+ "expired": "expiré"
189
+ "focused": "concentré"
190
+ "entered frame": "entré dans le cadre"
191
+ "exited frame": "sorti du cadre"
192
+ "hired": "embauché"
193
+ "interviewed": "interviewé"
194
+ "laughed": "ri"
195
+ "unread": "non lu"
196
+ "mentioned": "mentionné"
197
+ "mentored": "mentoré"
198
+ "paused": "mis en pause"
199
+ "performed": "effectué"
200
+ "personalized": "personnalisé"
201
+ "previewed": "prévisualisé"
202
+ "promoted": "promu"
203
+ "rated": "évalué"
204
+ "replied": "répondu"
205
+ "replied to tweet": "a répondu au tweet"
206
+ "requested attention": "a demandé de l'attention"
207
+ "retweeted": "retweeté"
208
+ "reviewed": "révisé"
209
+ "secured": "sécurisé"
210
+ "selected": "sélectionné"
211
+ "skipped": "passé"
212
+ "talked": "parlé"
213
+ "terminated employment with": "terminé l'emploi avec"
214
+ "tweeted": "tweeté"
215
+ "unfocused": "détourné"
216
+ "unregistered": "désinscrit"
217
+ "viewed": "vu"
218
+ "down voted": "voté contre"
219
+ "up voted": "voté pour"
220
+ "was assigned job title": "a reçu le titre de poste"
221
+ "was hired by": "a été embauché par"
222
+ "annotated": "annoté"
223
+ "modified annotation": "annotation modifiée"
224
+ "earned an Open Badge": "gagné un Open Badge"
225
+ "drew": "dessiné"
226
+ "cancelled planned learning": "a annulé l'apprentissage planifié"
227
+ "planned": "planifié"
228
+ "enrolled onto learning plan": "inscrit au plan d'apprentissage"
229
+ "evaluated": "évalué"
230
+ "log in": "connecté"
231
+ "log out": "déconnecté"
232
+ "ran": "couru"
233
+ "walked": "marché"
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ RailsXapi::Engine.routes.draw do
2
+ end
@@ -0,0 +1,16 @@
1
+ class CreateRailsXapiActors < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_actors do |t|
4
+ t.string :object_type, null: true
5
+ t.string :name, null: true
6
+ t.string :mbox, null: true
7
+ t.string :mbox_sha1sum, null: true
8
+ t.string :openid, null: true
9
+ t.datetime :created_at, null: false
10
+ end
11
+ end
12
+
13
+ def down
14
+ drop_table :rails_xapi_actors
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ class CreateRailsXapiAccounts < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_accounts do |t|
4
+ t.string :name, null: false
5
+ t.string :home_page, null: false
6
+ t.bigint :actor_id, null: false
7
+ end
8
+
9
+ add_index :rails_xapi_accounts, :actor_id
10
+ end
11
+
12
+ def down
13
+ drop_table :rails_xapi_accounts
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ class CreateRailsXapiVerbs < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_verbs, id: false do |t|
4
+ t.string :id, null: false, primary_key: true
5
+ t.string :display, null: true
6
+ end
7
+
8
+ add_index :rails_xapi_verbs, :id, unique: true
9
+ end
10
+
11
+ def down
12
+ drop_table :rails_xapi_verbs
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ class CreateRailsXapiObjects < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_objects, id: false do |t|
4
+ t.string :id, null: false, primary_key: true
5
+ t.string :object_type, null: false
6
+ t.bigint :statement_id, null: true
7
+ end
8
+
9
+ add_index :rails_xapi_objects, :id, unique: true
10
+ add_index :rails_xapi_objects, :statement_id
11
+ end
12
+
13
+ def down
14
+ drop_table :rails_xapi_objects
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ class CreateRailsXapiActivityDefinitions < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_activity_definitions do |t|
4
+ t.string :name, null: true
5
+ t.text :description, null: true
6
+ t.string :activity_type, null: true
7
+ t.text :more_info, null: true
8
+ t.string :object_id, null: false
9
+ end
10
+
11
+ add_index :rails_xapi_activity_definitions, :object_id
12
+ end
13
+
14
+ def down
15
+ drop_table :rails_xapi_activity_definitions
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ class CreateRailsXapiExtensions < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_extensions do |t|
4
+ t.string :iri, null: false
5
+ t.text :value, null: false
6
+ t.references :extendable, polymorphic: true
7
+ end
8
+ end
9
+
10
+ def down
11
+ drop_table :rails_xapi_extensions
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ class CreateRailsXapiStatements < ActiveRecord::Migration[7.1]
2
+ def up
3
+ create_table :rails_xapi_statements do |t|
4
+ t.string :actor_id, null: false
5
+ t.string :verb_id, null: false
6
+ t.string :object_id, null: false
7
+ t.datetime :timestamp, null: true
8
+ t.datetime :created_at, null: false
9
+ end
10
+
11
+ add_index :rails_xapi_statements, :actor_id
12
+ add_index :rails_xapi_statements, :verb_id
13
+ add_index :rails_xapi_statements, :object_id
14
+ end
15
+
16
+ def down
17
+ drop_table :rails_xapi_statements
18
+ end
19
+ end