Commit 8a86fe7bb0785ea69e591fd287430eb5448ac64e
Committed by
Dmitriy Zaporozhets
1 parent
f6c482c0
Exists in
master
and in
4 other branches
Added UserTeam core models (team and m-t-m relationships) and updated other models
Showing
14 changed files
with
249 additions
and
29 deletions
Show diff stats
app/models/concerns/issuable.rb
| ... | ... | @@ -22,6 +22,7 @@ module Issuable |
| 22 | 22 | scope :opened, where(closed: false) |
| 23 | 23 | scope :closed, where(closed: true) |
| 24 | 24 | scope :of_group, ->(group) { where(project_id: group.project_ids) } |
| 25 | + scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } | |
| 25 | 26 | scope :assigned, ->(u) { where(assignee_id: u.id)} |
| 26 | 27 | scope :recent, order("created_at DESC") |
| 27 | 28 | ... | ... |
app/models/project.rb
| ... | ... | @@ -33,28 +33,31 @@ class Project < ActiveRecord::Base |
| 33 | 33 | attr_accessor :error_code |
| 34 | 34 | |
| 35 | 35 | # Relations |
| 36 | - belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" | |
| 36 | + belongs_to :creator, foreign_key: "creator_id", class_name: "User" | |
| 37 | + belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" | |
| 37 | 38 | belongs_to :namespace |
| 38 | 39 | |
| 39 | - belongs_to :creator, | |
| 40 | - class_name: "User", | |
| 41 | - foreign_key: "creator_id" | |
| 42 | - | |
| 43 | - has_many :users, through: :users_projects | |
| 44 | - has_many :events, dependent: :destroy | |
| 45 | - has_many :merge_requests, dependent: :destroy | |
| 46 | - has_many :issues, dependent: :destroy, order: "closed, created_at DESC" | |
| 47 | - has_many :milestones, dependent: :destroy | |
| 48 | - has_many :users_projects, dependent: :destroy | |
| 49 | - has_many :notes, dependent: :destroy | |
| 50 | - has_many :snippets, dependent: :destroy | |
| 51 | - has_many :deploy_keys, dependent: :destroy, foreign_key: "project_id", class_name: "Key" | |
| 52 | - has_many :hooks, dependent: :destroy, class_name: "ProjectHook" | |
| 53 | - has_many :wikis, dependent: :destroy | |
| 54 | - has_many :protected_branches, dependent: :destroy | |
| 55 | 40 | has_one :last_event, class_name: 'Event', order: 'events.created_at DESC', foreign_key: 'project_id' |
| 56 | 41 | has_one :gitlab_ci_service, dependent: :destroy |
| 57 | 42 | |
| 43 | + has_many :events, dependent: :destroy | |
| 44 | + has_many :merge_requests, dependent: :destroy | |
| 45 | + has_many :issues, dependent: :destroy, order: "closed, created_at DESC" | |
| 46 | + has_many :milestones, dependent: :destroy | |
| 47 | + has_many :users_projects, dependent: :destroy | |
| 48 | + has_many :notes, dependent: :destroy | |
| 49 | + has_many :snippets, dependent: :destroy | |
| 50 | + has_many :deploy_keys, dependent: :destroy, class_name: "Key", foreign_key: "project_id" | |
| 51 | + has_many :hooks, dependent: :destroy, class_name: "ProjectHook" | |
| 52 | + has_many :wikis, dependent: :destroy | |
| 53 | + has_many :protected_branches, dependent: :destroy | |
| 54 | + has_many :user_team_project_relationships, dependent: :destroy | |
| 55 | + | |
| 56 | + has_many :users, through: :users_projects | |
| 57 | + has_many :user_teams, through: :user_team_project_relationships | |
| 58 | + has_many :user_team_user_relationships, through: :user_teams | |
| 59 | + has_many :user_teams_members, through: :user_team_user_relationships | |
| 60 | + | |
| 58 | 61 | delegate :name, to: :owner, allow_nil: true, prefix: true |
| 59 | 62 | |
| 60 | 63 | # Validations |
| ... | ... | @@ -77,6 +80,8 @@ class Project < ActiveRecord::Base |
| 77 | 80 | # Scopes |
| 78 | 81 | scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } |
| 79 | 82 | scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } |
| 83 | + scope :without_team, ->(team) { where("id NOT IN (:ids)", ids: team.projects.map(&:id)) } | |
| 84 | + scope :in_team, ->(team) { where("id IN (:ids)", ids: team.projects.map(&:id)) } | |
| 80 | 85 | scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) } |
| 81 | 86 | scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } |
| 82 | 87 | scope :personal, ->(user) { where(namespace_id: user.namespace_id) } | ... | ... |
app/models/user.rb
| ... | ... | @@ -45,18 +45,27 @@ class User < ActiveRecord::Base |
| 45 | 45 | attr_accessor :force_random_password |
| 46 | 46 | |
| 47 | 47 | # Namespace for personal projects |
| 48 | - has_one :namespace, class_name: "Namespace", foreign_key: :owner_id, conditions: 'type IS NULL', dependent: :destroy | |
| 49 | - has_many :groups, class_name: "Group", foreign_key: :owner_id | |
| 50 | - | |
| 51 | - has_many :keys, dependent: :destroy | |
| 52 | - has_many :users_projects, dependent: :destroy | |
| 53 | - has_many :issues, foreign_key: :author_id, dependent: :destroy | |
| 54 | - has_many :notes, foreign_key: :author_id, dependent: :destroy | |
| 55 | - has_many :merge_requests, foreign_key: :author_id, dependent: :destroy | |
| 56 | - has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy | |
| 57 | - has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" | |
| 58 | - has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy | |
| 59 | - has_many :assigned_merge_requests, class_name: "MergeRequest", foreign_key: :assignee_id, dependent: :destroy | |
| 48 | + has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL' | |
| 49 | + | |
| 50 | + has_many :keys, dependent: :destroy | |
| 51 | + has_many :users_projects, dependent: :destroy | |
| 52 | + has_many :issues, dependent: :destroy, foreign_key: :author_id | |
| 53 | + has_many :notes, dependent: :destroy, foreign_key: :author_id | |
| 54 | + has_many :merge_requests, dependent: :destroy, foreign_key: :author_id | |
| 55 | + has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" | |
| 56 | + has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" | |
| 57 | + has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" | |
| 58 | + | |
| 59 | + has_many :groups, class_name: "Group", foreign_key: :owner_id | |
| 60 | + has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC" | |
| 61 | + | |
| 62 | + has_many :projects, through: :users_projects | |
| 63 | + | |
| 64 | + has_many :user_team_user_relationships, dependent: :destroy | |
| 65 | + | |
| 66 | + has_many :user_teams, through: :user_team_user_relationships | |
| 67 | + has_many :user_team_project_relationships, through: :user_teams | |
| 68 | + has_many :team_projects, through: :user_team_project_relationships | |
| 60 | 69 | |
| 61 | 70 | validates :name, presence: true |
| 62 | 71 | validates :bio, length: { within: 0..255 } |
| ... | ... | @@ -80,6 +89,8 @@ class User < ActiveRecord::Base |
| 80 | 89 | scope :blocked, where(blocked: true) |
| 81 | 90 | scope :active, where(blocked: false) |
| 82 | 91 | scope :alphabetically, order('name ASC') |
| 92 | + scope :in_team, ->(team){ where(id: team.member_ids) } | |
| 93 | + scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } | |
| 83 | 94 | |
| 84 | 95 | # |
| 85 | 96 | # Class methods | ... | ... |
| ... | ... | @@ -0,0 +1,87 @@ |
| 1 | +class UserTeam < ActiveRecord::Base | |
| 2 | + attr_accessible :name, :owner_id, :path | |
| 3 | + | |
| 4 | + belongs_to :owner, class_name: User | |
| 5 | + | |
| 6 | + has_many :user_team_project_relationships, dependent: :destroy | |
| 7 | + has_many :user_team_user_relationships, dependent: :destroy | |
| 8 | + | |
| 9 | + has_many :projects, through: :user_team_project_relationships | |
| 10 | + has_many :members, through: :user_team_user_relationships, source: :user | |
| 11 | + | |
| 12 | + validates :name, presence: true, uniqueness: true | |
| 13 | + validates :owner, presence: true | |
| 14 | + validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, | |
| 15 | + format: { with: Gitlab::Regex.path_regex, | |
| 16 | + message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | |
| 17 | + | |
| 18 | + scope :with_member, ->(user){ joins(:user_team_user_relationships).where(user_team_user_relationships: {user_id: user.id}) } | |
| 19 | + scope :created_by, ->(user){ where(owner_id: user) } | |
| 20 | + | |
| 21 | + class << self | |
| 22 | + def search query | |
| 23 | + where("name LIKE :query OR path LIKE :query", query: "%#{query}%") | |
| 24 | + end | |
| 25 | + | |
| 26 | + def global_id | |
| 27 | + 'GLN' | |
| 28 | + end | |
| 29 | + | |
| 30 | + def access_roles | |
| 31 | + UsersProject.access_roles | |
| 32 | + end | |
| 33 | + end | |
| 34 | + | |
| 35 | + def to_param | |
| 36 | + path | |
| 37 | + end | |
| 38 | + | |
| 39 | + def assign_to_projects(projects, access) | |
| 40 | + projects.each do |project| | |
| 41 | + assign_to_project(project, access) | |
| 42 | + end | |
| 43 | + end | |
| 44 | + | |
| 45 | + def assign_to_project(project, access) | |
| 46 | + Gitlab::UserTeamManager.assign(self, project, access) | |
| 47 | + end | |
| 48 | + | |
| 49 | + def resign_from_project(project) | |
| 50 | + Gitlab::UserTeamManager.resign(self, project) | |
| 51 | + end | |
| 52 | + | |
| 53 | + def add_members(users, access, group_admin) | |
| 54 | + users.each do |user| | |
| 55 | + add_member(user, access, group_admin) | |
| 56 | + end | |
| 57 | + end | |
| 58 | + | |
| 59 | + def add_member(user, access, group_admin) | |
| 60 | + Gitlab::UserTeamManager.add_member_into_team(self, user, access, group_admin) | |
| 61 | + end | |
| 62 | + | |
| 63 | + def remove_member(user) | |
| 64 | + Gitlab::UserTeamManager.remove_member_from_team(self, user) | |
| 65 | + end | |
| 66 | + | |
| 67 | + def max_project_access(project) | |
| 68 | + user_team_project_relationships.find_by_project_id(project).greatest_access | |
| 69 | + end | |
| 70 | + | |
| 71 | + def human_max_project_access(project) | |
| 72 | + self.class.access_roles.invert[max_project_access(project)] | |
| 73 | + end | |
| 74 | + | |
| 75 | + def default_projects_access(member) | |
| 76 | + user_team_user_relationships.find_by_user_id(member).permission | |
| 77 | + end | |
| 78 | + | |
| 79 | + def human_default_projects_access(member) | |
| 80 | + self.class.access_roles.invert[default_projects_access(member)] | |
| 81 | + end | |
| 82 | + | |
| 83 | + def admin?(member) | |
| 84 | + user_team_user_relationships.with_user(member).first.group_admin? | |
| 85 | + end | |
| 86 | + | |
| 87 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | +class UserTeamProjectRelationship < ActiveRecord::Base | |
| 2 | + attr_accessible :greatest_access, :project_id, :user_team_id | |
| 3 | + | |
| 4 | + belongs_to :user_team | |
| 5 | + belongs_to :project | |
| 6 | + | |
| 7 | + validates :project, presence: true | |
| 8 | + validates :user_team, presence: true | |
| 9 | + validate :check_greatest_access | |
| 10 | + | |
| 11 | + scope :with_project, ->(project){ where(project_id: project.id) } | |
| 12 | + | |
| 13 | + private | |
| 14 | + | |
| 15 | + def check_greatest_access | |
| 16 | + errors.add(:base, :incorrect_access_code) unless correct_access? | |
| 17 | + end | |
| 18 | + | |
| 19 | + def correct_access? | |
| 20 | + return false if greatest_access.blank? | |
| 21 | + return true if UsersProject.access_roles.has_value?(greatest_access) | |
| 22 | + false | |
| 23 | + end | |
| 24 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | +class UserTeamUserRelationship < ActiveRecord::Base | |
| 2 | + attr_accessible :group_admin, :permission, :user_id, :user_team_id | |
| 3 | + | |
| 4 | + belongs_to :user_team | |
| 5 | + belongs_to :user | |
| 6 | + | |
| 7 | + validates :user_team, presence: true | |
| 8 | + validates :user, presence: true | |
| 9 | + | |
| 10 | + scope :with_user, ->(user) { where(user_id: user.id) } | |
| 11 | + | |
| 12 | + def user_name | |
| 13 | + user.name | |
| 14 | + end | |
| 15 | +end | ... | ... |
app/models/users_project.rb
| ... | ... | @@ -39,7 +39,10 @@ class UsersProject < ActiveRecord::Base |
| 39 | 39 | scope :reporters, where(project_access: REPORTER) |
| 40 | 40 | scope :developers, where(project_access: DEVELOPER) |
| 41 | 41 | scope :masters, where(project_access: MASTER) |
| 42 | + | |
| 42 | 43 | scope :in_project, ->(project) { where(project_id: project.id) } |
| 44 | + scope :in_projects, ->(projects) { where(project_id: projects.map(&:id)) } | |
| 45 | + scope :with_user, ->(user) { where(user_id: user.id) } | |
| 43 | 46 | |
| 44 | 47 | class << self |
| 45 | 48 | ... | ... |
db/migrate/20121220064104_create_user_team_project_relationships.rb
0 → 100644
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +class CreateUserTeamProjectRelationships < ActiveRecord::Migration | |
| 2 | + def change | |
| 3 | + create_table :user_team_project_relationships do |t| | |
| 4 | + t.integer :project_id | |
| 5 | + t.integer :user_team_id | |
| 6 | + t.integer :greatest_access | |
| 7 | + | |
| 8 | + t.timestamps | |
| 9 | + end | |
| 10 | + end | |
| 11 | +end | ... | ... |
db/migrate/20121220064453_create_user_team_user_relationships.rb
0 → 100644
| ... | ... | @@ -0,0 +1,12 @@ |
| 1 | +class CreateUserTeamUserRelationships < ActiveRecord::Migration | |
| 2 | + def change | |
| 3 | + create_table :user_team_user_relationships do |t| | |
| 4 | + t.integer :user_id | |
| 5 | + t.integer :user_team_id | |
| 6 | + t.boolean :group_admin | |
| 7 | + t.integer :permission | |
| 8 | + | |
| 9 | + t.timestamps | |
| 10 | + end | |
| 11 | + end | |
| 12 | +end | ... | ... |
db/schema.rb
| ... | ... | @@ -213,6 +213,31 @@ ActiveRecord::Schema.define(:version => 20130110172407) do |
| 213 | 213 | t.string "name" |
| 214 | 214 | end |
| 215 | 215 | |
| 216 | + create_table "user_team_project_relationships", :force => true do |t| | |
| 217 | + t.integer "project_id" | |
| 218 | + t.integer "user_team_id" | |
| 219 | + t.integer "greatest_access" | |
| 220 | + t.datetime "created_at", :null => false | |
| 221 | + t.datetime "updated_at", :null => false | |
| 222 | + end | |
| 223 | + | |
| 224 | + create_table "user_team_user_relationships", :force => true do |t| | |
| 225 | + t.integer "user_id" | |
| 226 | + t.integer "user_team_id" | |
| 227 | + t.boolean "group_admin" | |
| 228 | + t.integer "permission" | |
| 229 | + t.datetime "created_at", :null => false | |
| 230 | + t.datetime "updated_at", :null => false | |
| 231 | + end | |
| 232 | + | |
| 233 | + create_table "user_teams", :force => true do |t| | |
| 234 | + t.string "name" | |
| 235 | + t.string "path" | |
| 236 | + t.integer "owner_id" | |
| 237 | + t.datetime "created_at", :null => false | |
| 238 | + t.datetime "updated_at", :null => false | |
| 239 | + end | |
| 240 | + | |
| 216 | 241 | create_table "users", :force => true do |t| |
| 217 | 242 | t.string "email", :default => "", :null => false |
| 218 | 243 | t.string "encrypted_password", :default => "", :null => false | ... | ... |