cyclid 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +174 -0
- data/README.md +54 -0
- data/app/cyclid.rb +61 -0
- data/app/cyclid/config.rb +38 -0
- data/app/cyclid/controllers.rb +123 -0
- data/app/cyclid/controllers/auth.rb +34 -0
- data/app/cyclid/controllers/auth/token.rb +78 -0
- data/app/cyclid/controllers/health.rb +96 -0
- data/app/cyclid/controllers/organizations.rb +104 -0
- data/app/cyclid/controllers/organizations/collection.rb +134 -0
- data/app/cyclid/controllers/organizations/config.rb +128 -0
- data/app/cyclid/controllers/organizations/document.rb +135 -0
- data/app/cyclid/controllers/organizations/job.rb +266 -0
- data/app/cyclid/controllers/organizations/members.rb +145 -0
- data/app/cyclid/controllers/organizations/stages.rb +251 -0
- data/app/cyclid/controllers/users.rb +47 -0
- data/app/cyclid/controllers/users/collection.rb +131 -0
- data/app/cyclid/controllers/users/document.rb +133 -0
- data/app/cyclid/health_helpers.rb +40 -0
- data/app/cyclid/job.rb +3 -0
- data/app/cyclid/job/helpers.rb +67 -0
- data/app/cyclid/job/job.rb +164 -0
- data/app/cyclid/job/runner.rb +275 -0
- data/app/cyclid/job/stage.rb +67 -0
- data/app/cyclid/log_buffer.rb +104 -0
- data/app/cyclid/models.rb +3 -0
- data/app/cyclid/models/job_record.rb +25 -0
- data/app/cyclid/models/organization.rb +64 -0
- data/app/cyclid/models/plugin_config.rb +25 -0
- data/app/cyclid/models/stage.rb +42 -0
- data/app/cyclid/models/step.rb +29 -0
- data/app/cyclid/models/user.rb +60 -0
- data/app/cyclid/models/user_permissions.rb +28 -0
- data/app/cyclid/monkey_patches.rb +37 -0
- data/app/cyclid/plugin_registry.rb +75 -0
- data/app/cyclid/plugins.rb +125 -0
- data/app/cyclid/plugins/action.rb +48 -0
- data/app/cyclid/plugins/action/command.rb +89 -0
- data/app/cyclid/plugins/action/email.rb +207 -0
- data/app/cyclid/plugins/action/email/html.erb +58 -0
- data/app/cyclid/plugins/action/email/text.erb +13 -0
- data/app/cyclid/plugins/action/script.rb +90 -0
- data/app/cyclid/plugins/action/slack.rb +129 -0
- data/app/cyclid/plugins/action/slack/note.erb +5 -0
- data/app/cyclid/plugins/api.rb +195 -0
- data/app/cyclid/plugins/api/github.rb +111 -0
- data/app/cyclid/plugins/api/github/callback.rb +66 -0
- data/app/cyclid/plugins/api/github/methods.rb +201 -0
- data/app/cyclid/plugins/api/github/status.rb +67 -0
- data/app/cyclid/plugins/builder.rb +80 -0
- data/app/cyclid/plugins/builder/mist.rb +107 -0
- data/app/cyclid/plugins/dispatcher.rb +89 -0
- data/app/cyclid/plugins/dispatcher/local.rb +167 -0
- data/app/cyclid/plugins/provisioner.rb +40 -0
- data/app/cyclid/plugins/provisioner/debian.rb +90 -0
- data/app/cyclid/plugins/provisioner/ubuntu.rb +98 -0
- data/app/cyclid/plugins/source.rb +39 -0
- data/app/cyclid/plugins/source/git.rb +64 -0
- data/app/cyclid/plugins/transport.rb +63 -0
- data/app/cyclid/plugins/transport/ssh.rb +155 -0
- data/app/cyclid/sinatra/api_helpers.rb +66 -0
- data/app/cyclid/sinatra/auth_helpers.rb +127 -0
- data/app/cyclid/sinatra/warden/strategies/api_token.rb +62 -0
- data/app/cyclid/sinatra/warden/strategies/basic.rb +58 -0
- data/app/cyclid/sinatra/warden/strategies/hmac.rb +76 -0
- data/app/db.rb +51 -0
- data/bin/cyclid-db-init +107 -0
- data/db/schema.rb +92 -0
- data/lib/cyclid/app.rb +4 -0
- metadata +407 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Module for Cyclid Job related classes
|
21
|
+
module Job
|
22
|
+
# Non-AR model for Stages. Using a wrapper allows us to create an ad-hoc
|
23
|
+
# stage (I.e. one that is not stored in the database) or load a stage
|
24
|
+
# from the database and merge in over-rides without risking modifying
|
25
|
+
# the database object.
|
26
|
+
class StageView
|
27
|
+
attr_reader :name, :version, :steps
|
28
|
+
attr_accessor :on_success, :on_failure
|
29
|
+
|
30
|
+
def initialize(arg)
|
31
|
+
if arg.is_a? Cyclid::API::Stage
|
32
|
+
@name = arg.name
|
33
|
+
@version = arg.version
|
34
|
+
@steps = arg.steps.map(&:serializable_hash)
|
35
|
+
elsif arg.is_a? Hash
|
36
|
+
arg.symbolize_keys!
|
37
|
+
|
38
|
+
raise ArgumentError, 'name is required' unless arg.key? :name
|
39
|
+
|
40
|
+
@name = arg[:name]
|
41
|
+
@version = arg.fetch(:version, '1.0.0')
|
42
|
+
|
43
|
+
# Create & serialize Actions for each step
|
44
|
+
sequence = 1
|
45
|
+
@steps = arg[:steps].map do |step|
|
46
|
+
Cyclid.logger.debug "ad-hoc step=#{step}"
|
47
|
+
|
48
|
+
action_name = step['action']
|
49
|
+
plugin = Cyclid.plugins.find(action_name, Cyclid::API::Plugins::Action)
|
50
|
+
|
51
|
+
step_action = plugin.new(step)
|
52
|
+
raise ArgumentError if step_action.nil?
|
53
|
+
|
54
|
+
# Serialize the object into the Step and store it in the database.
|
55
|
+
action = Oj.dump(step_action)
|
56
|
+
|
57
|
+
step_definition = { sequence: sequence, action: action }
|
58
|
+
sequence += 1
|
59
|
+
|
60
|
+
step_definition
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Simple in-memory FIFO; inspired by StringIO but reads & writes maintain
|
21
|
+
# their own position. It's unlike a file enough to not be derived from IO.
|
22
|
+
class StringFIFO
|
23
|
+
def initialize
|
24
|
+
@buffer = String.new
|
25
|
+
@write_pos = 0
|
26
|
+
@read_pos = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
# Append data to the buffer & update the write position
|
30
|
+
def write(data)
|
31
|
+
@buffer += data
|
32
|
+
@write_pos += data.length
|
33
|
+
end
|
34
|
+
|
35
|
+
# Read data from the buffer. If length is given, read at most length
|
36
|
+
# characters from the buffer or whatever is available, whichever is
|
37
|
+
# smaller.
|
38
|
+
#
|
39
|
+
# Completely non-blocking; if no data is available, returns an empty
|
40
|
+
# string.
|
41
|
+
def read(length = nil)
|
42
|
+
len = if length
|
43
|
+
[length, @write_pos].min
|
44
|
+
else
|
45
|
+
@write_pos
|
46
|
+
end
|
47
|
+
start = @read_pos
|
48
|
+
@read_pos += len
|
49
|
+
|
50
|
+
@buffer[start, len]
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return the entire contents of the buffer
|
54
|
+
def string
|
55
|
+
@buffer
|
56
|
+
end
|
57
|
+
|
58
|
+
alias to_s string
|
59
|
+
|
60
|
+
# Reset the buffer, read & write positions
|
61
|
+
def clear
|
62
|
+
@buffer = ''
|
63
|
+
@write_pos = 0
|
64
|
+
@read_pos = 0
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Intelligent buffer which can be passed to plugins which need to collate
|
69
|
+
# output data from different commands during a job
|
70
|
+
class LogBuffer
|
71
|
+
def initialize(job_record = nil, websocket = nil)
|
72
|
+
@job_record = job_record
|
73
|
+
@websocket = websocket
|
74
|
+
@buffer = StringFIFO.new
|
75
|
+
end
|
76
|
+
|
77
|
+
# Append data to the log and send it on to any configured consumers
|
78
|
+
def write(data)
|
79
|
+
# Append the new data to log
|
80
|
+
@buffer.write data
|
81
|
+
|
82
|
+
# Update the Job Record, if there is one
|
83
|
+
if @job_record
|
84
|
+
# XXX: This will destroy the database. Find a better method.
|
85
|
+
@job_record.log = @buffer.string
|
86
|
+
@job_record.save!
|
87
|
+
end
|
88
|
+
|
89
|
+
# Write to web socket
|
90
|
+
@websocket.write data if @websocket
|
91
|
+
end
|
92
|
+
|
93
|
+
# Non-destructively read any new data from the buffer
|
94
|
+
def read(length = nil)
|
95
|
+
@buffer.read(length)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return a complete copy of the data from the buffer
|
99
|
+
def log
|
100
|
+
@buffer.string
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for Users
|
21
|
+
class JobRecord < ActiveRecord::Base
|
22
|
+
Cyclid.logger.debug('In the JobRecod model')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for Organizations
|
21
|
+
class Organization < ActiveRecord::Base
|
22
|
+
Cyclid.logger.debug('In the Organization model')
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Return the collection of Organizations as an array of Hashes (instead
|
26
|
+
# of Organization objects)
|
27
|
+
def all_as_hash
|
28
|
+
all.to_a.map(&:serializable_hash)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
validates :name, presence: true
|
33
|
+
validates :owner_email, presence: true
|
34
|
+
|
35
|
+
validates :rsa_private_key, presence: true
|
36
|
+
validates :rsa_public_key, presence: true
|
37
|
+
validates :salt, presence: true
|
38
|
+
|
39
|
+
validates_uniqueness_of :name
|
40
|
+
|
41
|
+
has_and_belongs_to_many :users,
|
42
|
+
after_add: :add_user_org_perm,
|
43
|
+
after_remove: :remove_user_org_perm
|
44
|
+
|
45
|
+
has_many :userpermissions
|
46
|
+
has_many :stages
|
47
|
+
has_many :job_records
|
48
|
+
has_many :plugin_configs
|
49
|
+
|
50
|
+
# Ensure that a set of Userpermissions exist when a User is added to
|
51
|
+
# this Organization
|
52
|
+
def add_user_org_perm(user)
|
53
|
+
Cyclid.logger.debug "Creating org. perm. for #{user.username}"
|
54
|
+
user.userpermissions << Userpermission.new(organization: self)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Remove Userpermissions when a User is removed from this Organization
|
58
|
+
def remove_user_org_perm(user)
|
59
|
+
Cyclid.logger.debug "Destroying org. perm. for #{user.username}"
|
60
|
+
user.userpermissions.delete(Userpermission.find_by(organization: self))
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for PluginConfigs
|
21
|
+
class PluginConfig < ActiveRecord::Base
|
22
|
+
belongs_to :organization
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for Stages
|
21
|
+
class Stage < ActiveRecord::Base
|
22
|
+
Cyclid.logger.debug('In the Stage model')
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Return the collection of Stages as an array of Hashes (instead
|
26
|
+
# of Stage objects)
|
27
|
+
def all_as_hash
|
28
|
+
all.to_a.map(&:serializable_hash)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
validates :name, presence: true
|
33
|
+
validates :version, presence: true
|
34
|
+
|
35
|
+
validates_uniqueness_of :name, scope: :version
|
36
|
+
validates_format_of :version, with: /\A\d+.\d+.\d+.?\d*\z/
|
37
|
+
|
38
|
+
belongs_to :organization
|
39
|
+
has_many :steps
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for Steps
|
21
|
+
class Step < ActiveRecord::Base
|
22
|
+
Cyclid.logger.debug('In the Step model')
|
23
|
+
|
24
|
+
validates :sequence, presence: true
|
25
|
+
|
26
|
+
belongs_to :stage
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
require 'bcrypt'
|
17
|
+
|
18
|
+
# Top level module for the core Cyclid code.
|
19
|
+
module Cyclid
|
20
|
+
# Module for the Cyclid API
|
21
|
+
module API
|
22
|
+
# Model for Users
|
23
|
+
class User < ActiveRecord::Base
|
24
|
+
Cyclid.logger.debug('In the User model')
|
25
|
+
|
26
|
+
class << self
|
27
|
+
# Return the collection of Users as an array of Hashes (instead
|
28
|
+
# of User objects)
|
29
|
+
def all_as_hash
|
30
|
+
all.to_a.map(&:serializable_hash)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
validates :username, presence: true
|
35
|
+
validates :email, presence: true
|
36
|
+
|
37
|
+
validates_uniqueness_of :username
|
38
|
+
|
39
|
+
has_and_belongs_to_many :organizations
|
40
|
+
has_many :userpermissions
|
41
|
+
has_many :job_records
|
42
|
+
|
43
|
+
# Allow an unencryped password to be passed in via. new_password and
|
44
|
+
# ensure it is encrypted into password when the record is saved
|
45
|
+
attr_accessor :new_password
|
46
|
+
|
47
|
+
before_save :hash_new_password, if: :password_changed?
|
48
|
+
|
49
|
+
# Check if the new_password attribute has changed
|
50
|
+
def password_changed?
|
51
|
+
!@new_password.blank?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Generate a BCrypt2 password from the plaintext
|
55
|
+
def hash_new_password
|
56
|
+
self.password = BCrypt::Password.create(@new_password)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Copyright 2016 Liqwyd Ltd.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
# Top level module for the core Cyclid code.
|
17
|
+
module Cyclid
|
18
|
+
# Module for the Cyclid API
|
19
|
+
module API
|
20
|
+
# Model for UserPermissions
|
21
|
+
class Userpermission < ActiveRecord::Base
|
22
|
+
Cyclid.logger.debug('In the Userpermission model')
|
23
|
+
|
24
|
+
belongs_to :user
|
25
|
+
belongs_to :organization
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|