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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +152 -0
- data/Rakefile +8 -0
- data/app/controllers/rails_xapi/application_controller.rb +7 -0
- data/app/helpers/rails_xapi/application_helper.rb +26 -0
- data/app/jobs/rails_xapi/application_job.rb +4 -0
- data/app/jobs/rails_xapi/create_statement_job.rb +11 -0
- data/app/mailers/rails_xapi/application_mailer.rb +6 -0
- data/app/models/concerns/serializable.rb +14 -0
- data/app/models/rails_xapi/account.rb +27 -0
- data/app/models/rails_xapi/activity_definition.rb +143 -0
- data/app/models/rails_xapi/actor.rb +227 -0
- data/app/models/rails_xapi/application_record.rb +5 -0
- data/app/models/rails_xapi/context.rb +163 -0
- data/app/models/rails_xapi/context_activity.rb +37 -0
- data/app/models/rails_xapi/errors/xapi_error.rb +4 -0
- data/app/models/rails_xapi/extension.rb +29 -0
- data/app/models/rails_xapi/group_member.rb +21 -0
- data/app/models/rails_xapi/interaction_activity.rb +103 -0
- data/app/models/rails_xapi/interaction_component.rb +34 -0
- data/app/models/rails_xapi/object.rb +150 -0
- data/app/models/rails_xapi/result.rb +174 -0
- data/app/models/rails_xapi/statement.rb +62 -0
- data/app/models/rails_xapi/validators/language_map_validator.rb +64 -0
- data/app/models/rails_xapi/verb.rb +260 -0
- data/app/services/application_service.rb +16 -0
- data/app/services/rails_xapi/query.rb +217 -0
- data/app/services/rails_xapi/statement_creator.rb +53 -0
- data/app/views/layouts/rails_xapi/application.html.erb +12 -0
- data/config/locales/rails_xapi.en.yml +43 -0
- data/config/locales/rails_xapi.fr.yml +233 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20240716144226_create_rails_xapi_actors.rb +16 -0
- data/db/migrate/20240716144227_create_rails_xapi_accounts.rb +15 -0
- data/db/migrate/20240716144228_create_rails_xapi_verbs.rb +14 -0
- data/db/migrate/20240716144229_create_rails_xapi_objects.rb +16 -0
- data/db/migrate/20240716144230_create_rails_xapi_activity_definitions.rb +17 -0
- data/db/migrate/20240716144231_create_rails_xapi_extensions.rb +13 -0
- data/db/migrate/20240716144232_create_rails_xapi_statements.rb +19 -0
- data/db/migrate/20240716144233_create_rails_xapi_results.rb +21 -0
- data/db/migrate/20240716144234_create_rails_xapi_contexts.rb +23 -0
- data/db/migrate/20240716144235_create_rails_xapi_context_activities.rb +16 -0
- data/db/migrate/20240716144236_create_rails_xapi_group_members.rb +16 -0
- data/db/migrate/20250522093846_create_rails_xapi_interaction_activities.rb +15 -0
- data/db/migrate/20250522122830_create_rails_xapi_interaction_component.rb +16 -0
- data/lib/rails-xapi/configuration.rb +13 -0
- data/lib/rails-xapi/engine.rb +28 -0
- data/lib/rails-xapi/version.rb +5 -0
- data/lib/rails-xapi.rb +16 -0
- data/lib/tasks/auto_annotate_models.rake +62 -0
- data/lib/tasks/rails-xapi_tasks.rake +4 -0
- 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,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,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
|