obscured-timeline 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +28 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +14 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.simplecov +4 -0
- data/.travis.yml +17 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +70 -0
- data/README.md +94 -0
- data/lib/obscured-timeline.rb +18 -0
- data/lib/obscured-timeline/record.rb +73 -0
- data/lib/obscured-timeline/service.rb +53 -0
- data/lib/obscured-timeline/tracker.rb +137 -0
- data/lib/obscured-timeline/version.rb +7 -0
- data/obscured-timeline.gemspec +32 -0
- data/spec/account_service_spec.rb +82 -0
- data/spec/config/mongoid.yml +11 -0
- data/spec/factories/event_factory.rb +25 -0
- data/spec/helpers/account_document.rb +11 -0
- data/spec/helpers/account_service.rb +9 -0
- data/spec/helpers/organization_document.rb +11 -0
- data/spec/setup.rb +39 -0
- data/spec/tracker_multiple_spec.rb +109 -0
- data/spec/tracker_single_spec.rb +127 -0
- metadata +163 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0e1584c8287352150fb7ec886112dadb191da1dda84f12221c17d02b9ea3b56
|
4
|
+
data.tar.gz: 6db5ea73e99f2d7ee20bbbe14d9e2ff36752dd32e8f4487345fd252966c7bd34
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d447fec014fe51a9d58397bccbc79b0754fccf8102e80fe3a36a4ec2b111101a3958b11baa6415c237f9724f8c00727d0bedd075987894b2f8b38653eba3801f
|
7
|
+
data.tar.gz: a457a5e1aac0222ab6c3b144294faf4c64b0621f11fed394cdd2a069aaf1c59b6535e45bfe186a023922e5ad34c0a8f5ee0d6ee3ce69bd75797d901aab752fbc
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
version: "2"
|
2
|
+
checks:
|
3
|
+
complex-logic:
|
4
|
+
config:
|
5
|
+
threshold: 10
|
6
|
+
file-lines:
|
7
|
+
enabled: false
|
8
|
+
method-complexity:
|
9
|
+
config:
|
10
|
+
threshold: 15
|
11
|
+
method-lines:
|
12
|
+
config:
|
13
|
+
threshold: 250
|
14
|
+
similar-code:
|
15
|
+
enabled: false
|
16
|
+
plugins:
|
17
|
+
rubocop:
|
18
|
+
enabled: true
|
19
|
+
channel: rubocop-0-71
|
20
|
+
coffeelint:
|
21
|
+
enabled: true
|
22
|
+
eslint:
|
23
|
+
enabled: true
|
24
|
+
csslint:
|
25
|
+
enabled: true
|
26
|
+
exclude_patterns:
|
27
|
+
- "tests/"
|
28
|
+
- "spec/"
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Metrics/AbcSize:
|
2
|
+
Max: 50
|
3
|
+
Metrics/ClassLength:
|
4
|
+
Enabled: false
|
5
|
+
Metrics/CyclomaticComplexity:
|
6
|
+
Max: 15
|
7
|
+
Metrics/LineLength:
|
8
|
+
Enabled: false
|
9
|
+
Metrics/MethodLength:
|
10
|
+
Enabled: false
|
11
|
+
Metrics/PerceivedComplexity:
|
12
|
+
Max: 15
|
13
|
+
Naming/FileName:
|
14
|
+
Enabled: false
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
obscured-timeline
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/.simplecov
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
env:
|
2
|
+
global:
|
3
|
+
- CC_TEST_REPORTER_ID=2a254563f48d490eab9b9e9682ea30c8b13d221d06bb1fed6e3c045124b49e6c
|
4
|
+
language: ruby
|
5
|
+
bundler_args: --with development
|
6
|
+
rvm:
|
7
|
+
- 2.6.3
|
8
|
+
services:
|
9
|
+
- mongodb
|
10
|
+
before_script:
|
11
|
+
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
12
|
+
- chmod +x ./cc-test-reporter
|
13
|
+
- ./cc-test-reporter before-build
|
14
|
+
script:
|
15
|
+
- bundle exec rspec
|
16
|
+
after_script:
|
17
|
+
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
obscured-timeline (1.0.0)
|
5
|
+
activesupport
|
6
|
+
mongoid
|
7
|
+
mongoid_search
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activemodel (6.0.2.2)
|
13
|
+
activesupport (= 6.0.2.2)
|
14
|
+
activesupport (6.0.2.2)
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
i18n (>= 0.7, < 2)
|
17
|
+
minitest (~> 5.1)
|
18
|
+
tzinfo (~> 1.1)
|
19
|
+
zeitwerk (~> 2.2)
|
20
|
+
bson (4.8.2)
|
21
|
+
concurrent-ruby (1.1.6)
|
22
|
+
diff-lcs (1.3)
|
23
|
+
docile (1.3.2)
|
24
|
+
factory_bot (5.1.1)
|
25
|
+
activesupport (>= 4.2.0)
|
26
|
+
fast-stemmer (1.0.2)
|
27
|
+
i18n (1.8.2)
|
28
|
+
concurrent-ruby (~> 1.0)
|
29
|
+
minitest (5.14.0)
|
30
|
+
mongo (2.11.4)
|
31
|
+
bson (>= 4.4.2, < 5.0.0)
|
32
|
+
mongoid (7.1.0)
|
33
|
+
activemodel (>= 5.1, < 6.1)
|
34
|
+
mongo (>= 2.7.0, < 3.0.0)
|
35
|
+
mongoid_search (0.3.6)
|
36
|
+
fast-stemmer (~> 1.0.0)
|
37
|
+
mongoid (>= 3.0.0)
|
38
|
+
rspec (3.9.0)
|
39
|
+
rspec-core (~> 3.9.0)
|
40
|
+
rspec-expectations (~> 3.9.0)
|
41
|
+
rspec-mocks (~> 3.9.0)
|
42
|
+
rspec-core (3.9.1)
|
43
|
+
rspec-support (~> 3.9.1)
|
44
|
+
rspec-expectations (3.9.1)
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
+
rspec-support (~> 3.9.0)
|
47
|
+
rspec-mocks (3.9.1)
|
48
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
+
rspec-support (~> 3.9.0)
|
50
|
+
rspec-support (3.9.2)
|
51
|
+
simplecov (0.18.5)
|
52
|
+
docile (~> 1.1)
|
53
|
+
simplecov-html (~> 0.11)
|
54
|
+
simplecov-html (0.12.2)
|
55
|
+
thread_safe (0.3.6)
|
56
|
+
tzinfo (1.2.6)
|
57
|
+
thread_safe (~> 0.1)
|
58
|
+
zeitwerk (2.3.0)
|
59
|
+
|
60
|
+
PLATFORMS
|
61
|
+
ruby
|
62
|
+
|
63
|
+
DEPENDENCIES
|
64
|
+
factory_bot
|
65
|
+
obscured-timeline!
|
66
|
+
rspec
|
67
|
+
simplecov
|
68
|
+
|
69
|
+
BUNDLED WITH
|
70
|
+
2.1.4
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
[![Vulnerabilities](https://snyk.io/test/github/gonace/obscured.timeline/badge.svg)](https://snyk.io/test/github/gonace/obscured.timeline)
|
2
|
+
[![Build Status](https://travis-ci.org/gonace/Obscured.Timeline.svg?branch=master)](https://travis-ci.org/gonace/Obscured.Timeline)
|
3
|
+
[![Test Coverage](https://codeclimate.com/github/gonace/Obscured.Timeline/badges/coverage.svg)](https://codeclimate.com/github/gonace/Obscured.Timeline)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/gonace/Obscured.Timeline/badges/gpa.svg)](https://codeclimate.com/github/gonace/Obscured.Timeline)
|
5
|
+
|
6
|
+
# Obscured::Timeline
|
7
|
+
## Introduction
|
8
|
+
Obscured timeline adds event to a separate collection for an entity (Document), the naming of the class (Mongoid Document) is used for naming the timeline collection, so if the class is named "Account" the collection name will end up being "account_timeline".
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
### Requirements
|
12
|
+
- activesupport
|
13
|
+
- mongoid
|
14
|
+
- mongoid_search
|
15
|
+
|
16
|
+
##### Add this line to your application's Gemfile
|
17
|
+
```ruby
|
18
|
+
gem 'obscured-timeline', :git => 'https://github.com/gonace/Obscured.Timeline.git', :branch => 'master'
|
19
|
+
```
|
20
|
+
|
21
|
+
##### Execute
|
22
|
+
```
|
23
|
+
$ bundle
|
24
|
+
```
|
25
|
+
|
26
|
+
### Usage
|
27
|
+
#### Base
|
28
|
+
Use this in files where you create non-default log collections.
|
29
|
+
```ruby
|
30
|
+
require 'obscured-timeline'
|
31
|
+
```
|
32
|
+
|
33
|
+
|
34
|
+
### Example
|
35
|
+
#### Document
|
36
|
+
```ruby
|
37
|
+
require 'obscured-timeline'
|
38
|
+
|
39
|
+
module Obscured
|
40
|
+
class Account
|
41
|
+
include Mongoid::Document
|
42
|
+
include Mongoid::Timestamps
|
43
|
+
include Obscured::Timeline::Tracker
|
44
|
+
|
45
|
+
field :name, type: String
|
46
|
+
field :email, type: String
|
47
|
+
field :locked, type: Boolean, default: false
|
48
|
+
end
|
49
|
+
|
50
|
+
def lock!
|
51
|
+
self.locked = true
|
52
|
+
self.add_event(type: :security, message: "Account has been locked!", producer: self.username)
|
53
|
+
save
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
account = Obscured::Account.create(:name => "John Doe", :email => "john.doe@obscured.se")
|
59
|
+
event = account.add_event(type: :comment, message: "Lorem ipsum dolor sit amet?", producer: "homer.simpson@obscured.se")
|
60
|
+
|
61
|
+
#returns array of events for document (proprietor)
|
62
|
+
account.get_events
|
63
|
+
|
64
|
+
#returns event by id
|
65
|
+
account.get_event(event.id.to_s)
|
66
|
+
|
67
|
+
#returns array of events by predefined params, supports pagination
|
68
|
+
account.find_events({ type: nil, producer: nil }, { limit: 20, skip: 0, order: :created_at.desc, only: [:id, :type, :message, :producer, :created_at, :updated_at, :proprietor] })
|
69
|
+
|
70
|
+
#retuns array of events
|
71
|
+
account.search_events("homer.simpson@obscured.se", { type: :comment, limit: 20, skip: 0, order: :created_at.desc })
|
72
|
+
```
|
73
|
+
|
74
|
+
#### Service
|
75
|
+
```ruby
|
76
|
+
module Obscured
|
77
|
+
class AccountTimelineService
|
78
|
+
include Mongoid::Timeline::Service::Base
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module Obscured
|
83
|
+
class AccountSynchronizer
|
84
|
+
def initialize(account)
|
85
|
+
@account = account
|
86
|
+
@service = Obscured::AccountTimelineService.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def timeline
|
90
|
+
@service.by(proprietor: { account_id: account.id })
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'mongoid_search'
|
5
|
+
|
6
|
+
Mongoid::Search.setup do |cfg|
|
7
|
+
cfg.strip_symbols = /["]/
|
8
|
+
cfg.strip_accents = //
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'obscured-timeline/record'
|
12
|
+
require 'obscured-timeline/service'
|
13
|
+
require 'obscured-timeline/tracker'
|
14
|
+
|
15
|
+
module Mongoid
|
16
|
+
module Timeline
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'mongoid_search'
|
5
|
+
|
6
|
+
module Mongoid
|
7
|
+
module Timeline
|
8
|
+
module Record
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
include Mongoid::Document
|
13
|
+
include Mongoid::Search
|
14
|
+
include Mongoid::Timestamps
|
15
|
+
|
16
|
+
field :type, type: Symbol
|
17
|
+
field :severity, type: Symbol, default: :informational
|
18
|
+
field :message, type: String
|
19
|
+
field :producer, type: String
|
20
|
+
field :proprietor, type: Hash
|
21
|
+
|
22
|
+
index({ type: 1 }, background: true)
|
23
|
+
index({ producer: 1 }, background: true)
|
24
|
+
index({ _keywords: 1 }, background: true)
|
25
|
+
|
26
|
+
search_in :id, :type, :producer
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def make(params = {})
|
31
|
+
raise ArgumentError, 'type missing' if params[:type].blank?
|
32
|
+
raise ArgumentError, 'type must be a symbol' unless params[:type].instance_of?(Symbol)
|
33
|
+
raise ArgumentError, 'message missing' if params[:message].nil?
|
34
|
+
raise ArgumentError, 'producer missing' if params[:producer].blank?
|
35
|
+
raise ArgumentError, 'proprietor missing' if params[:proprietor].blank?
|
36
|
+
|
37
|
+
doc = new
|
38
|
+
doc.type = params[:type]
|
39
|
+
doc.severity = params[:severity].to_sym unless params[:severity].blank?
|
40
|
+
doc.message = params[:message]
|
41
|
+
doc.producer = params[:producer]
|
42
|
+
doc.proprietor = params[:proprietor]
|
43
|
+
doc
|
44
|
+
end
|
45
|
+
|
46
|
+
def make!(params = {})
|
47
|
+
doc = make(params)
|
48
|
+
doc.save!
|
49
|
+
doc
|
50
|
+
end
|
51
|
+
|
52
|
+
def by(params = {}, options = {})
|
53
|
+
limit = options[:limit].blank? ? nil : options[:limit].to_i
|
54
|
+
skip = options[:skip].blank? ? nil : options[:skip].to_i
|
55
|
+
order = options[:order].blank? ? :created_at.desc : options[:order]
|
56
|
+
only = options[:only].blank? ? %i[id type message producer created_at updated_at proprietor] : options[:only]
|
57
|
+
|
58
|
+
query = {}
|
59
|
+
query[:type] = params[:type].to_sym if params[:type]
|
60
|
+
query[:severity] = params[:severity].to_sym if params[:severity]
|
61
|
+
query[:producer] = params[:producer].to_sym if params[:producer]
|
62
|
+
params[:proprietor]&.map { |k, v| query.merge!("proprietor.#{k}" => v) }
|
63
|
+
|
64
|
+
criterion = where(query).only(only).limit(limit).skip(skip)
|
65
|
+
criterion = criterion.order_by(order) if order
|
66
|
+
|
67
|
+
docs = criterion.to_a
|
68
|
+
docs
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Timeline
|
5
|
+
module Service
|
6
|
+
module Base
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
def all(criterion = {})
|
12
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
13
|
+
m.all(criterion).to_a
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(*args)
|
18
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
19
|
+
m.find(*args)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_by(attrs = {})
|
24
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
25
|
+
m.find_by(attrs).to_a
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def where(expression)
|
30
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
31
|
+
m.where(expression).to_a
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def by(params = {}, options = {})
|
36
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
37
|
+
m.by(params, options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(id)
|
42
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
43
|
+
m.where(id: id).delete
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Record
|
48
|
+
include Mongoid::Timeline::Record
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module Mongoid
|
6
|
+
module Timeline
|
7
|
+
module Tracker
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
class Record
|
11
|
+
include Mongoid::Timeline::Record
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds event to the x_timeline collection for document. This is
|
15
|
+
# only called on manually.
|
16
|
+
#
|
17
|
+
# @example Add event.
|
18
|
+
# document.add_event
|
19
|
+
#
|
20
|
+
# @return [ document ]
|
21
|
+
def add_event(event)
|
22
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
23
|
+
m.make!(event.merge(proprietor: { "#{self.class.name.demodulize.downcase}_id".to_sym => id }))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get an event from the x_timeline collection for document. This is
|
28
|
+
# only called on manually.
|
29
|
+
#
|
30
|
+
# @example Get event.
|
31
|
+
# document.get_event(id)
|
32
|
+
#
|
33
|
+
# @return [ document ]
|
34
|
+
def get_event(id)
|
35
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
36
|
+
m.find(id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get events from the x_timeline collection for document by proprietor. This is
|
41
|
+
# only called on manually.
|
42
|
+
#
|
43
|
+
# @example Get event.
|
44
|
+
# document.get_events
|
45
|
+
# document.events
|
46
|
+
#
|
47
|
+
# @return [ documents ]
|
48
|
+
def get_events
|
49
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
50
|
+
m.by(proprietor: { "#{self.class.name.demodulize.downcase}_id".to_sym => id })
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias events get_events
|
54
|
+
|
55
|
+
# Find events from the x_timeline collection for document. This is
|
56
|
+
# only called on manually.
|
57
|
+
#
|
58
|
+
# @example Get event.
|
59
|
+
# document.find_events(params, options)
|
60
|
+
#
|
61
|
+
# @return [ documents ]
|
62
|
+
def find_events(params, options)
|
63
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
64
|
+
m.by({ proprietor: { "#{self.class.name.demodulize.downcase}_id".to_sym => id } }.merge(params), options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Search events from the x_timeline collection for document. This is
|
69
|
+
# only called on manually.
|
70
|
+
#
|
71
|
+
# @example Get event.
|
72
|
+
# document.search_events(text, options)
|
73
|
+
#
|
74
|
+
# @return [ documents ]
|
75
|
+
def search_events(text, options)
|
76
|
+
limit = options[:limit].blank? ? nil : options[:limit].to_i
|
77
|
+
skip = options[:skip].blank? ? nil : options[:skip].to_i
|
78
|
+
order = options[:order].blank? ? :created_at.desc : options[:order]
|
79
|
+
|
80
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
81
|
+
query = {}
|
82
|
+
query[:type] = options[:type].to_sym if options[:type]
|
83
|
+
query[:severity] = options[:severity].to_sym if options[:severity]
|
84
|
+
|
85
|
+
criteria = m.where(query).full_text_search(text)
|
86
|
+
criteria = criteria.order_by(order) if order
|
87
|
+
criteria = criteria.limit(limit).skip(skip)
|
88
|
+
|
89
|
+
docs = criteria.to_a
|
90
|
+
docs
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Edit an event from the x_timeline collection by id. This is
|
95
|
+
# only called on manually.
|
96
|
+
#
|
97
|
+
# @example Get event.
|
98
|
+
# document.edit_event(id, params)
|
99
|
+
#
|
100
|
+
# @return [ document ]
|
101
|
+
def edit_event(id, params = {})
|
102
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
103
|
+
event = m.where(id: id).first
|
104
|
+
event.message = params[:message] if params[:message]
|
105
|
+
event.save
|
106
|
+
event
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Delete an event from the x_timeline collection by id. This is
|
111
|
+
# only called on manually.
|
112
|
+
#
|
113
|
+
# @example Get event.
|
114
|
+
# document.get_event(id)
|
115
|
+
#
|
116
|
+
# @return [ document ]
|
117
|
+
def delete_event(id)
|
118
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
119
|
+
m.where(id: id).delete
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Clear events from the x_timeline collection for document. This is
|
124
|
+
# only called on manually.
|
125
|
+
#
|
126
|
+
# @example Get event.
|
127
|
+
# document.clear_events
|
128
|
+
#
|
129
|
+
# @return [ documents ]
|
130
|
+
def clear_events
|
131
|
+
Record.with(collection: "#{self.class.name.demodulize.downcase}_timeline") do |m|
|
132
|
+
m.where(proprietor: { "#{self.class.name.demodulize.downcase}_id".to_sym => id }).delete
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'obscured-timeline/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.name = 'obscured-timeline'
|
9
|
+
gem.version = Mongoid::Timeline::VERSION
|
10
|
+
gem.platform = Gem::Platform::RUBY
|
11
|
+
gem.licenses = ['MIT']
|
12
|
+
gem.authors = ['Erik Hennerfors']
|
13
|
+
gem.email = ['erik.hennerfors@obscured.se']
|
14
|
+
gem.description = 'Mongoid extension to handles a timeline of events for an entity (e.g. User)'
|
15
|
+
gem.summary = 'Mongoid extension that adds the ability to handle events in a timeline for a entity (e.g. User)'
|
16
|
+
gem.homepage = 'https://github.com/gonace/Obscured.Timeline'
|
17
|
+
|
18
|
+
gem.required_ruby_version = '>= 2'
|
19
|
+
|
20
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
21
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
22
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
23
|
+
gem.require_paths = ['lib']
|
24
|
+
|
25
|
+
gem.add_dependency 'activesupport'
|
26
|
+
gem.add_dependency 'mongoid'
|
27
|
+
gem.add_dependency 'mongoid_search'
|
28
|
+
|
29
|
+
gem.add_development_dependency 'factory_bot'
|
30
|
+
gem.add_development_dependency 'rspec'
|
31
|
+
gem.add_development_dependency 'simplecov'
|
32
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'setup'
|
4
|
+
require_relative 'helpers/account_document'
|
5
|
+
require_relative 'helpers/account_service'
|
6
|
+
|
7
|
+
|
8
|
+
describe Mongoid::Timeline::Service::Account do
|
9
|
+
let!(:account) { Obscured::Account.new(email: 'homer.simpsons@obscured.se') }
|
10
|
+
let!(:message) { 'Praesent a massa dui. Etiam eget purus consequat, mollis erat et, rhoncus tortor.' }
|
11
|
+
let!(:service) { Mongoid::Timeline::Service::Account.new }
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
2.times do
|
15
|
+
account.add_event(type: :event, message: message, producer: account.email)
|
16
|
+
end
|
17
|
+
5.times do
|
18
|
+
account.add_event(type: :comment, message: message, producer: account.email)
|
19
|
+
end
|
20
|
+
5.times do
|
21
|
+
account.add_event(type: :change, message: message, producer: account.email)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'all' do
|
26
|
+
let(:response) { service.all }
|
27
|
+
|
28
|
+
it { expect(response.count).to eq(12) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'find' do
|
32
|
+
let!(:event) { account.add_event(type: :change, message: message, producer: account.id) }
|
33
|
+
let(:response) { service.find(event.id) }
|
34
|
+
|
35
|
+
it { expect(response).to_not be(nil) }
|
36
|
+
it { expect(response.id).to eq(event.id) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'find_by' do
|
40
|
+
let!(:event) { account.add_event(type: :change, message: message, producer: account.id) }
|
41
|
+
let(:response) { service.find_by(type: :change) }
|
42
|
+
|
43
|
+
it { expect(response).to_not be(nil) }
|
44
|
+
it { expect(response.count).to eq(1) }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'by' do
|
48
|
+
context 'proprietor' do
|
49
|
+
let(:response) { service.by(proprietor: { account_id: account.id }) }
|
50
|
+
|
51
|
+
it { expect(response.length).to eq(12) }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'type' do
|
55
|
+
let(:response) { service.by(type: :comment) }
|
56
|
+
|
57
|
+
it { expect(response.count).to eq(5) }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'proprietor and type' do
|
61
|
+
let(:response) { service.by(type: :event, proprietor: { account_id: account.id }) }
|
62
|
+
|
63
|
+
it { expect(response.length).to eq(2) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'where' do
|
68
|
+
context 'returns correct documents' do
|
69
|
+
let(:response) { service.where(type: :event) }
|
70
|
+
|
71
|
+
it { expect(response.count).to eq(2) }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'delete' do
|
76
|
+
context 'deletes document by id' do
|
77
|
+
let!(:event) { account.add_event(type: :change, message: message, producer: account.id) }
|
78
|
+
|
79
|
+
it { expect(service.delete(event.id.to_s)).to eq(1) }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../lib/obscured-timeline/record'
|
4
|
+
|
5
|
+
FactoryBot.define do
|
6
|
+
factory :event, class: Mongoid::Timeline::Record do
|
7
|
+
type { :comment }
|
8
|
+
message { 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' }
|
9
|
+
producer { 'homer.simpson@obscured.se' }
|
10
|
+
proprietor { {} }
|
11
|
+
|
12
|
+
|
13
|
+
trait :as_comment do
|
14
|
+
type { :comment }
|
15
|
+
end
|
16
|
+
|
17
|
+
trait :as_change do
|
18
|
+
type { :change }
|
19
|
+
end
|
20
|
+
|
21
|
+
trait :with_account do
|
22
|
+
proprietor { { account_id: BSON::ObjectId.new } }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/setup.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Pull in test utilities
|
4
|
+
require 'simplecov'
|
5
|
+
require 'factory_bot'
|
6
|
+
require 'pp'
|
7
|
+
require 'rspec'
|
8
|
+
|
9
|
+
# pull in the code
|
10
|
+
require_relative '../lib/obscured-timeline'
|
11
|
+
|
12
|
+
Mongoid.load!(File.join(File.dirname(__FILE__), '/config/mongoid.yml'), 'spec')
|
13
|
+
Mongo::Logger.logger.level = Logger::ERROR
|
14
|
+
|
15
|
+
RSpec.configure do |c|
|
16
|
+
c.order = :random
|
17
|
+
c.filter_run :focus
|
18
|
+
c.run_all_when_everything_filtered = true
|
19
|
+
|
20
|
+
c.include FactoryBot::Syntax::Methods
|
21
|
+
|
22
|
+
c.before(:suite) do
|
23
|
+
FactoryBot.find_definitions
|
24
|
+
Mongoid.purge!
|
25
|
+
|
26
|
+
Mongoid::Search.setup do |cfg|
|
27
|
+
cfg.strip_symbols = /["]/
|
28
|
+
cfg.strip_accents = //
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
c.before(:each) do
|
33
|
+
Mongoid.purge!
|
34
|
+
end
|
35
|
+
|
36
|
+
c.after(:suite) do
|
37
|
+
Mongoid.purge!
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'setup'
|
4
|
+
require_relative 'helpers/account_document'
|
5
|
+
require_relative 'helpers/organization_document'
|
6
|
+
|
7
|
+
|
8
|
+
describe Mongoid::Timeline::Tracker do
|
9
|
+
let!(:account_email) { 'homer.simpson@obscured.se' }
|
10
|
+
let!(:message) { 'Praesent a massa dui. Etiam eget purus consequat, mollis erat et, rhoncus tortor.' }
|
11
|
+
let(:account) { Obscured::Account.new(email: account_email) }
|
12
|
+
let(:organization) { Obscured::Organization.new(name: 'adeprimose') }
|
13
|
+
|
14
|
+
describe 'write event' do
|
15
|
+
context 'validates that that events is written to correct collection' do
|
16
|
+
before(:each) do
|
17
|
+
account.save!
|
18
|
+
organization.save
|
19
|
+
end
|
20
|
+
let!(:account_event) { account.add_event(type: :comment, message: message, producer: account.email) }
|
21
|
+
let!(:organization_event) { organization.add_event(type: :change, message: message, producer: account.email) }
|
22
|
+
|
23
|
+
context 'for account' do
|
24
|
+
it { expect(account_event.type).to eq(:comment) }
|
25
|
+
it { expect(account_event.message).to eq(message) }
|
26
|
+
it { expect(account_event.proprietor).to eq(account_id: account.id) }
|
27
|
+
|
28
|
+
context 'get event' do
|
29
|
+
let!(:event) { account.add_event(type: :comment, message: message, producer: account.email) }
|
30
|
+
let!(:response) { account.get_event(event.id) }
|
31
|
+
|
32
|
+
it { expect(response.id).to eq(event.id) }
|
33
|
+
it { expect(response.type).to eq(event.type) }
|
34
|
+
it { expect(response.message).to eq(event.message) }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'get events' do
|
38
|
+
let!(:response) { account.get_events }
|
39
|
+
|
40
|
+
it { expect(response.count).to eq(1) }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'find events' do
|
44
|
+
let!(:event) { account.add_event(type: :comment, message: message, producer: account.email) }
|
45
|
+
let!(:event2) { account.add_event(type: :foobar, message: message, producer: account.email) }
|
46
|
+
let!(:event3) { account.add_event(type: :foobar, message: message, producer: account.email) }
|
47
|
+
let!(:response) { account.find_events({ type: :foobar }, { }) }
|
48
|
+
|
49
|
+
it { expect(response.count).to eq(2) }
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'search events' do
|
53
|
+
before(:each) do
|
54
|
+
10.times do
|
55
|
+
account.add_event(type: :comment, message: message, producer: account.email)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
let!(:event) { account.add_event(type: :comment, message: message, producer: account.email) }
|
60
|
+
let!(:event2) { account.add_event(type: :comment, message: message, producer: account.email) }
|
61
|
+
let!(:response) { account.search_events(account.email, limit: 5) }
|
62
|
+
|
63
|
+
it { expect(response.count).to eq(5) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'for organization' do
|
68
|
+
it { expect(organization_event.type).to eq(:change) }
|
69
|
+
it { expect(organization_event.message).to eq(message) }
|
70
|
+
it { expect(organization_event.proprietor).to eq(organization_id: organization.id) }
|
71
|
+
|
72
|
+
context 'get event' do
|
73
|
+
let!(:event) { organization.add_event(type: :comment, message: message, producer: organization.id) }
|
74
|
+
let!(:response) { organization.get_event(event.id) }
|
75
|
+
|
76
|
+
it { expect(response.id).to eq(event.id) }
|
77
|
+
it { expect(response.type).to eq(event.type) }
|
78
|
+
it { expect(response.message).to eq(event.message) }
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'get events' do
|
82
|
+
let!(:response) { organization.get_events }
|
83
|
+
|
84
|
+
it { expect(response.count).to eq(1) }
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'find events' do
|
88
|
+
let!(:event) { organization.add_event(type: :comment, message: message, producer: organization.id) }
|
89
|
+
let!(:event2) { organization.add_event(type: :foobar, message: message, producer: organization.id) }
|
90
|
+
let!(:event3) { organization.add_event(type: :foobar, message: message, producer: organization.id) }
|
91
|
+
let!(:response) { account.find_events({ type: :comment }, limit: 1) }
|
92
|
+
|
93
|
+
it { expect(response.count).to eq(1) }
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'search events' do
|
97
|
+
before(:each) do
|
98
|
+
10.times do
|
99
|
+
organization.add_event(type: :comment, message: message, producer: organization.id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
let!(:response) { organization.search_events(organization.id, limit: 5) }
|
103
|
+
|
104
|
+
it { expect(response.count).to eq(5) }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'setup'
|
4
|
+
require_relative 'helpers/account_document'
|
5
|
+
|
6
|
+
|
7
|
+
describe Mongoid::Timeline::Tracker do
|
8
|
+
let!(:account_email) { 'homer.simpson@obscured.se' }
|
9
|
+
let!(:type) { :comment }
|
10
|
+
let!(:message) { 'Praesent a massa dui. Etiam eget purus consequat, mollis erat et, rhoncus tortor.' }
|
11
|
+
let(:account) { Obscured::Account.new(email: account_email) }
|
12
|
+
|
13
|
+
describe 'event' do
|
14
|
+
before(:each) do
|
15
|
+
account.save!
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'add event' do
|
19
|
+
let!(:event) { account.add_event(type: type, message: message, producer: account.id) }
|
20
|
+
|
21
|
+
it { expect(event.type).to eq(type) }
|
22
|
+
it { expect(event.message).to eq(message) }
|
23
|
+
it { expect(event.proprietor).to eq(account_id: account.id) }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'get event' do
|
27
|
+
let!(:event) { account.add_event(type: type, message: message, producer: account.id) }
|
28
|
+
let(:response) { account.get_event(event.id) }
|
29
|
+
|
30
|
+
it { expect(response.id).to eq(event.id) }
|
31
|
+
it { expect(response.type).to eq(event.type) }
|
32
|
+
it { expect(response.message).to eq(event.message) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'get events' do
|
36
|
+
let!(:event) { account.add_event(type: type, message: message, producer: account.id) }
|
37
|
+
let!(:event2) { account.add_event(type: type, message: message, producer: account.id) }
|
38
|
+
let(:response) { account.get_events }
|
39
|
+
|
40
|
+
it { expect(response.count).to eq(2) }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'find events' do
|
44
|
+
let(:response) { account.find_events({ type: :comment }, { }) }
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
account.add_event(type: :comment, message: message, producer: account.id)
|
48
|
+
account.add_event(type: :comment, message: message, producer: account.id)
|
49
|
+
account.add_event(type: :foobar, message: message, producer: account.id)
|
50
|
+
end
|
51
|
+
|
52
|
+
it { expect(response.count).to eq(2) }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'search events' do
|
56
|
+
before(:each) do
|
57
|
+
5.times do
|
58
|
+
account.add_event(type: :payment, message: message, producer: account.id)
|
59
|
+
end
|
60
|
+
|
61
|
+
10.times do
|
62
|
+
account.add_event(type: :comment, message: message, producer: account.id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with limit' do
|
67
|
+
let(:response) { account.search_events(account.id, limit: 5) }
|
68
|
+
|
69
|
+
it { expect(response.count).to eq(5) }
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'with limit and type' do
|
73
|
+
let(:response) { account.search_events(account.id, limit: 10, type: :payment) }
|
74
|
+
|
75
|
+
it { expect(response.count).to eq(10) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'edit event' do
|
80
|
+
let!(:event) { account.add_event(type: type, message: message, producer: account.id) }
|
81
|
+
|
82
|
+
context 'updates message for the event' do
|
83
|
+
before(:each) do
|
84
|
+
account.edit_event(event.id, message: 'This is is a new message')
|
85
|
+
end
|
86
|
+
|
87
|
+
it { expect(account.get_event(event.id).message).to eq('This is is a new message') }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'delete event' do
|
92
|
+
let!(:event) { account.add_event(type: type, message: message, producer: account.id) }
|
93
|
+
|
94
|
+
context 'deletes the event' do
|
95
|
+
before(:each) do
|
96
|
+
account.delete_event(event.id)
|
97
|
+
end
|
98
|
+
|
99
|
+
it { expect(account.get_event(event.id)).to be_nil }
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'clear events' do
|
104
|
+
before(:each) do
|
105
|
+
2.times do
|
106
|
+
account.add_event(type: :event, message: message, producer: account.email)
|
107
|
+
end
|
108
|
+
5.times do
|
109
|
+
account.add_event(type: :comment, message: message, producer: account.email)
|
110
|
+
end
|
111
|
+
5.times do
|
112
|
+
account.add_event(type: :change, message: message, producer: account.email)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it { expect(account.get_events.count).to be(12) }
|
117
|
+
|
118
|
+
context 'clear all event' do
|
119
|
+
before(:each) do
|
120
|
+
account.clear_events
|
121
|
+
end
|
122
|
+
|
123
|
+
it { expect(account.get_events.count).to be(0) }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: obscured-timeline
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erik Hennerfors
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongoid
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mongoid_search
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: factory_bot
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Mongoid extension to handles a timeline of events for an entity (e.g.
|
98
|
+
User)
|
99
|
+
email:
|
100
|
+
- erik.hennerfors@obscured.se
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".codeclimate.yml"
|
106
|
+
- ".gitignore"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- ".ruby-gemset"
|
109
|
+
- ".ruby-version"
|
110
|
+
- ".simplecov"
|
111
|
+
- ".travis.yml"
|
112
|
+
- Gemfile
|
113
|
+
- Gemfile.lock
|
114
|
+
- README.md
|
115
|
+
- lib/obscured-timeline.rb
|
116
|
+
- lib/obscured-timeline/record.rb
|
117
|
+
- lib/obscured-timeline/service.rb
|
118
|
+
- lib/obscured-timeline/tracker.rb
|
119
|
+
- lib/obscured-timeline/version.rb
|
120
|
+
- obscured-timeline.gemspec
|
121
|
+
- spec/account_service_spec.rb
|
122
|
+
- spec/config/mongoid.yml
|
123
|
+
- spec/factories/event_factory.rb
|
124
|
+
- spec/helpers/account_document.rb
|
125
|
+
- spec/helpers/account_service.rb
|
126
|
+
- spec/helpers/organization_document.rb
|
127
|
+
- spec/setup.rb
|
128
|
+
- spec/tracker_multiple_spec.rb
|
129
|
+
- spec/tracker_single_spec.rb
|
130
|
+
homepage: https://github.com/gonace/Obscured.Timeline
|
131
|
+
licenses:
|
132
|
+
- MIT
|
133
|
+
metadata: {}
|
134
|
+
post_install_message:
|
135
|
+
rdoc_options: []
|
136
|
+
require_paths:
|
137
|
+
- lib
|
138
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '2'
|
143
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
requirements: []
|
149
|
+
rubygems_version: 3.0.3
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Mongoid extension that adds the ability to handle events in a timeline for
|
153
|
+
a entity (e.g. User)
|
154
|
+
test_files:
|
155
|
+
- spec/account_service_spec.rb
|
156
|
+
- spec/config/mongoid.yml
|
157
|
+
- spec/factories/event_factory.rb
|
158
|
+
- spec/helpers/account_document.rb
|
159
|
+
- spec/helpers/account_service.rb
|
160
|
+
- spec/helpers/organization_document.rb
|
161
|
+
- spec/setup.rb
|
162
|
+
- spec/tracker_multiple_spec.rb
|
163
|
+
- spec/tracker_single_spec.rb
|