Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #32

Merged
merged 6 commits into from
Dec 6, 2024
Merged

Dev #32

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions app/helpers/rails_xapi/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ def duration_to_minutes(duration)
end

# Output the value of a JSON row in a specific locale.
def json_value_for_locale(json, locale = I18n.locale)
hash = JSON.parse(json)
def json_value_for_locale(json_str, locale = I18n.locale)
hash = JSON.parse(json_str)
result = hash.select { |key, _value| key.include?(locale.to_s) }
result.values.first.to_s || hash.first.value.to_s
rescue
json_str
end

# Output the result score as a percentage.
Expand Down
31 changes: 26 additions & 5 deletions app/models/rails_xapi/actor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class RailsXapi::Actor < ApplicationRecord

OBJECT_TYPES = ["Agent", "Group"]

attr_accessor :objectType
attr_accessor :objectType, :member

has_one :account, class_name: "RailsXapi::Account", dependent: :destroy
has_many :statements, class_name: "RailsXapi::Statement", dependent: :nullify
Expand All @@ -18,13 +18,14 @@ class RailsXapi::Actor < ApplicationRecord

after_initialize :set_defaults
before_validation :normalize_actor
after_commit :create_members, if: :is_group?

# Build the Actor object from the given data and user email.
#
# @param [Hash] data The data used to build the actor object, including optional nested account data.
# @param [String] user_email The optional email address to be included in the `mbox` field of the data.
# @return [RailsXapi::Actor] The actor object initialized with the data.
def self.build_from_data(data, user_email = nil)
def self.build_actor_from_data(data, user_email = nil)
data = data.merge(mbox: "mailto:#{user_email}") if user_email.present?
data = handle_account_data(data)

Expand Down Expand Up @@ -68,6 +69,11 @@ def to_hash
def set_defaults
# We need to match the camel case notation from JSON data.
self.object_type = objectType.presence || object_type.presence || OBJECT_TYPES.first
self.member = member.presence || nil
end

def is_group?
object_type === "Group"
end

# Normalizes the actor data.
Expand Down Expand Up @@ -149,9 +155,24 @@ def validate_openid
# @param [String] mbox The mbox clear value to be encoded.
# @return [Boolean] True if the value is matching, false otherwise.
def is_sha1?(str)
# SHA-1 hash is a 40-character hexadecimal string
# consisting of numbers 0-9 and letters a-f
!!(str =~ /^sha1:[0-9a-f]{40}$/i)
# SHA-1 hash is a 40-character hexadecimal string consisting of numbers 0-9 and letters a-f.
# We also handle the case with an optional "sha1" prefix.
!!(str =~ /^(sha1:)?[0-9a-f]{40}$/i)
end

# Create members in the case of a "Group" objectType.
def create_members
# We should end the function here when we create a group without members (ex: a team in the context object).
return if member.blank?

raise RailsXapi::Errors::XapiError, I18n.t("rails_xapi.errors.failed_to_create_group_members") if id.blank?

member.each do |m|
new_actor = RailsXapi::Actor.by_iri_or_create(m)
RailsXapi::GroupMember.create(group_id: id, actor_id: new_actor.id)
rescue => _
raise RailsXapi::Errors::XapiError, I18n.t("rails_xapi.errors.failed_to_create_member", member: m)
end
end
end

Expand Down
6 changes: 6 additions & 0 deletions app/models/rails_xapi/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ def validate_data
raise RailsXapi::Errors::XapiError, I18n.t("rails_xapi.errors.attribute_must_be_a_hash", name: "extensions")
end
end

def parsed_value
JSON.parse(value.gsub("=>", ":"))
rescue
value
end
end

# == Schema Information
Expand Down
6 changes: 6 additions & 0 deletions app/models/rails_xapi/group_member.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class RailsXapi::GroupMember < ApplicationRecord
belongs_to :group, class_name: "RailsXapi::Actor", dependent: :destroy
belongs_to :actor, class_name: "RailsXapi::Actor", dependent: :destroy
end
9 changes: 9 additions & 0 deletions app/models/rails_xapi/result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ def score=(value)
self.score_max = value[:max]
end

def score
{
scaled: score_scaled,
raw: score_raw,
min: score_min,
max: score_max
}.compact
end

# Transform a duration in seconds into a ISO 8601 string.
# This is an optional attribute meant to bring more convenience for some systems.
#
Expand Down
14 changes: 14 additions & 0 deletions app/services/rails_xapi/query_statement.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

# This class manages the query interface for actors.
class RailsXapi::QueryStatement < ApplicationService
def self.by_actor_emails_and_object_id(actor_emails = [], object_id)
raise ArgumentError, I18n.t("rails_xapi.errors.malformed_email") unless actor_emails.any?

mailto_emails = actor_emails.map do |email|
email.start_with?("mailto:") ? email : "mailto:#{email}"
end

RailsXapi::Statement.includes([:actor, :verb, :object, :result]).where(actor: {mbox: mailto_emails}, object: {id: object_id})
end
end
2 changes: 1 addition & 1 deletion app/services/rails_xapi/statement_creator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def call_async
def prepare_statement
# Send the user infos from the call if passed to it.
user_email = @user.nil? ? nil : @user.presence[:email]
actor = RailsXapi::Actor.build_from_data(@data[:actor], user_email)
actor = RailsXapi::Actor.build_actor_from_data(@data[:actor], user_email)

verb = RailsXapi::Verb.find_or_create_by(id: @data[:verb][:id]) do |v|
v.display = @data[:verb][:display]
Expand Down
1 change: 1 addition & 0 deletions config/locales/rails_xapi.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ en:
couldnt_create_the_substatement: "couldn’t create the substatement"
definition_description_invalid_keys: "invalid keys in definition description: %{values}"
definition_description_must_be_language_map: "definition description must be a language map"
failed_to_create_member: "failed to create member: #{member}"
invalid_actor: "invalid actor"
invalid_actor_object_type: "invalid actor's object type: %{name}"
invalid_object_object_type: "invalid object's object type: %{name}"
Expand Down
5 changes: 5 additions & 0 deletions config/locales/rails_xapi.fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ fr:
couldnt_create_the_substatement: "la sous-déclaration n'a pas pu être créée"
definition_description_invalid_keys: "clés incorrectes dans la description de définition : %{values}"
definition_description_must_be_language_map: "la description de définitionde doit être de type language map"
failed_to_create_member: "échec de création d'un membre : #{member}"
invalid_actor: "acteur invalide"
invalid_actor_object_type: "type d'objet de l'acteur incorrect : %{name}"
invalid_object_object_type: "type d'objet de l'objet incorrect : %{name}"
Expand Down Expand Up @@ -41,6 +42,10 @@ fr:
actor: "acteur"
agent: "agent"
context: "contexte"
context_registration: "enregistrement"
context_parent: "parent"
context_category: "catégorie"
context_other: "autre"
group: "groupe"
object: "objet"
result: "résultat"
Expand Down
16 changes: 16 additions & 0 deletions db/migrate/20240716144236_create_rails_xapi_group_members.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CreateRailsXapiGroupMembers < ActiveRecord::Migration[7.1]
def up
create_table :rails_xapi_group_members do |t|
t.bigint :group_id, null: false
t.bigint :actor_id, null: false
t.datetime :created_at, null: false
end

add_index :rails_xapi_group_members, :group_id
add_index :rails_xapi_group_members, :actor_id
end

def down
drop_table :rails_xapi_group_members
end
end
4 changes: 2 additions & 2 deletions spec/models/rails_xapi/actor_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
end

it "should build an actor from data" do
actor = RailsXapi::Actor.build_from_data(@complete_actor, "actor@example.com")
actor = RailsXapi::Actor.build_actor_from_data(@complete_actor, "actor@example.com")

expect(actor.valid?).to be_truthy
end

it "should create the correct hash of the actor's data" do
actor = RailsXapi::Actor.build_from_data(@complete_actor, "actor@example.com")
actor = RailsXapi::Actor.build_actor_from_data(@complete_actor, "actor@example.com")

expect(actor.to_hash[:objectType]).to eq("Agent")
end
Expand Down
Loading