commit
37fd9670a5
@ -0,0 +1,7 @@ |
|||||||
|
# frozen_string_literal: true |
||||||
|
|
||||||
|
class Settings::LoginActivitiesController < Settings::BaseController |
||||||
|
def index |
||||||
|
@login_activities = LoginActivity.where(user: current_user).order(id: :desc).page(params[:page]) |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,35 @@ |
|||||||
|
# frozen_string_literal: true |
||||||
|
# == Schema Information |
||||||
|
# |
||||||
|
# Table name: login_activities |
||||||
|
# |
||||||
|
# id :bigint(8) not null, primary key |
||||||
|
# user_id :bigint(8) not null |
||||||
|
# authentication_method :string |
||||||
|
# provider :string |
||||||
|
# success :boolean |
||||||
|
# failure_reason :string |
||||||
|
# ip :inet |
||||||
|
# user_agent :string |
||||||
|
# created_at :datetime |
||||||
|
# |
||||||
|
|
||||||
|
class LoginActivity < ApplicationRecord |
||||||
|
enum authentication_method: { password: 'password', otp: 'otp', webauthn: 'webauthn', sign_in_token: 'sign_in_token', omniauth: 'omniauth' } |
||||||
|
|
||||||
|
belongs_to :user |
||||||
|
|
||||||
|
validates :authentication_method, inclusion: { in: authentication_methods.keys } |
||||||
|
|
||||||
|
def detection |
||||||
|
@detection ||= Browser.new(user_agent) |
||||||
|
end |
||||||
|
|
||||||
|
def browser |
||||||
|
detection.id |
||||||
|
end |
||||||
|
|
||||||
|
def platform |
||||||
|
detection.platform.id |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,17 @@ |
|||||||
|
- method_str = content_tag(:span, login_activity.omniauth? ? t(login_activity.provider, scope: 'auth.providers') : t(login_activity.authentication_method, scope: 'login_activities.authentication_methods'), class: 'target') |
||||||
|
- ip_str = content_tag(:span, login_activity.ip, class: 'target') |
||||||
|
- browser_str = content_tag(:span, t('sessions.description', browser: t("sessions.browsers.#{login_activity.browser}", default: "#{login_activity.browser}"), platform: t("sessions.platforms.#{login_activity.platform}", default: "#{login_activity.platform}")), class: 'target') |
||||||
|
|
||||||
|
.log-entry |
||||||
|
.log-entry__header |
||||||
|
.log-entry__avatar |
||||||
|
.indicator-icon{ class: login_activity.success? ? 'success' : 'failure' } |
||||||
|
= fa_icon login_activity.success? ? 'check' : 'times' |
||||||
|
.log-entry__content |
||||||
|
.log-entry__title |
||||||
|
- if login_activity.success? |
||||||
|
= t('login_activities.successful_sign_in_html', method: method_str, ip: ip_str, browser: browser_str) |
||||||
|
- else |
||||||
|
= t('login_activities.failed_sign_in_html', method: method_str, ip: ip_str, browser: browser_str) |
||||||
|
.log-entry__timestamp |
||||||
|
%time.formatted{ datetime: login_activity.created_at.iso8601 } |
@ -0,0 +1,15 @@ |
|||||||
|
- content_for :page_title do |
||||||
|
= t 'login_activities.title' |
||||||
|
|
||||||
|
%p= t('login_activities.description_html') |
||||||
|
|
||||||
|
%hr.spacer/ |
||||||
|
|
||||||
|
- if @login_activities.empty? |
||||||
|
%div.muted-hint.center-text |
||||||
|
= t 'login_activities.empty' |
||||||
|
- else |
||||||
|
.announcements-list |
||||||
|
= render partial: 'login_activity', collection: @login_activities |
||||||
|
|
||||||
|
= paginate @login_activities |
@ -0,0 +1,14 @@ |
|||||||
|
class CreateLoginActivities < ActiveRecord::Migration[6.1] |
||||||
|
def change |
||||||
|
create_table :login_activities do |t| |
||||||
|
t.belongs_to :user, null: false, foreign_key: { on_delete: :cascade } |
||||||
|
t.string :authentication_method |
||||||
|
t.string :provider |
||||||
|
t.boolean :success |
||||||
|
t.string :failure_reason |
||||||
|
t.inet :ip |
||||||
|
t.string :user_agent |
||||||
|
t.datetime :created_at |
||||||
|
end |
||||||
|
end |
||||||
|
end |
@ -0,0 +1,8 @@ |
|||||||
|
Fabricator(:login_activity) do |
||||||
|
user |
||||||
|
strategy 'password' |
||||||
|
success true |
||||||
|
failure_reason nil |
||||||
|
ip { Faker::Internet.ip_v4_address } |
||||||
|
user_agent { Faker::Internet.user_agent } |
||||||
|
end |
@ -0,0 +1,5 @@ |
|||||||
|
require 'rails_helper' |
||||||
|
|
||||||
|
RSpec.describe LoginActivity, type: :model do |
||||||
|
|
||||||
|
end |
Loading…
Reference in new issue