diff --git a/models/access_test.go b/models/access_test.go
index e06db5607b..6b3cce502c 100644
--- a/models/access_test.go
+++ b/models/access_test.go
@@ -106,7 +106,7 @@ func TestRepository_RecalculateAccesses(t *testing.T) {
 	has, err := x.Get(access)
 	assert.NoError(t, err)
 	assert.True(t, has)
-	assert.Equal(t, AccessModeWrite, access.Mode)
+	assert.Equal(t, AccessModeOwner, access.Mode)
 }
 
 func TestRepository_RecalculateAccesses2(t *testing.T) {
diff --git a/models/fixtures/org_user.yml b/models/fixtures/org_user.yml
index b4df3c0127..a7b8d178aa 100644
--- a/models/fixtures/org_user.yml
+++ b/models/fixtures/org_user.yml
@@ -5,3 +5,27 @@
   is_public: true
   is_owner: true
   num_teams: 1
+
+-
+  id: 2
+  uid: 4
+  org_id: 3
+  is_public: false
+  is_owner: false
+  num_teams: 0
+
+-
+  id: 3
+  uid: 5
+  org_id: 6
+  is_public: true
+  is_owner: true
+  num_teams: 1
+
+-
+  id: 4
+  uid: 5
+  org_id: 7
+  is_public: false
+  is_owner: true
+  num_teams: 1
diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml
index 00b0077283..c415f20732 100644
--- a/models/fixtures/repository.yml
+++ b/models/fixtures/repository.yml
@@ -41,3 +41,15 @@
   num_closed_issues: 0
   num_pulls: 0
   num_closed_pulls: 0
+
+-
+  id: 5
+  owner_id: 3
+  lower_name: repo5
+  name: repo5
+  is_private: true
+  num_issues: 0
+  num_closed_issues: 0
+  num_pulls: 0
+  num_closed_pulls: 0
+  is_mirror: true
diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml
index 9746f50d81..99e228efeb 100644
--- a/models/fixtures/team.yml
+++ b/models/fixtures/team.yml
@@ -1,7 +1,35 @@
 -
   id: 1
   org_id: 3
+  lower_name: owners
+  name: owners
+  authorize: 4 # owner
+  num_repos: 1
+  num_members: 1
+
+-
+  id: 2
+  org_id: 3
   lower_name: team1
   name: team1
   authorize: 2 # write
   num_repos: 1
+  num_members: 2
+
+-
+  id: 3
+  org_id: 6
+  lower_name: owners
+  name: owners
+  authorize: 4 # owner
+  num_repos: 0
+  num_members: 1
+
+-
+  id: 4
+  org_id: 7
+  lower_name: owners
+  name: owners
+  authorize: 4 # owner
+  num_repos: 0
+  num_members: 1
diff --git a/models/fixtures/team_repo.yml b/models/fixtures/team_repo.yml
index b954ae8c10..1f7385e7e9 100644
--- a/models/fixtures/team_repo.yml
+++ b/models/fixtures/team_repo.yml
@@ -3,3 +3,15 @@
   org_id: 3
   team_id: 1
   repo_id: 3
+
+-
+  id: 2
+  org_id: 3
+  team_id: 2
+  repo_id: 3
+
+-
+  id: 3
+  org_id: 3
+  team_id: 1
+  repo_id: 5
diff --git a/models/fixtures/team_user.yml b/models/fixtures/team_user.yml
index e569f9f3d9..955a80e4cd 100644
--- a/models/fixtures/team_user.yml
+++ b/models/fixtures/team_user.yml
@@ -3,3 +3,27 @@
   org_id: 3
   team_id: 1
   uid: 2
+
+-
+  id: 2
+  org_id: 3
+  team_id: 2
+  uid: 2
+
+-
+  id: 3
+  org_id: 3
+  team_id: 2
+  uid: 4
+
+-
+  id: 4
+  org_id: 6
+  team_id: 3
+  uid: 5
+
+-
+  id: 5
+  org_id: 7
+  team_id: 4
+  uid: 5
diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml
index a38b4016e3..aa1d80d6f0 100644
--- a/models/fixtures/user.yml
+++ b/models/fixtures/user.yml
@@ -38,7 +38,8 @@
   is_admin: false
   avatar: avatar3
   avatar_email: user3@example.com
-  num_repos: 1
+  num_repos: 2
+  num_members: 2
 
 -
   id: 4
@@ -47,7 +48,7 @@
   full_name: User Four
   email: user4@example.com
   passwd: password
-  type: 1 # individual
+  type: 0 # individual
   salt: salt
   is_admin: false
   avatar: avatar4
@@ -61,9 +62,40 @@
   full_name: User Five
   email: user5@example.com
   passwd: password
-  type: 1 # individual
+  type: 0 # individual
   salt: salt
   is_admin: false
   avatar: avatar5
   avatar_email: user5@example.com
   num_repos: 1
+  allow_create_organization: false
+
+-
+  id: 6
+  lower_name: user6
+  name: user6
+  full_name: User Six
+  email: user6@example.com
+  passwd: password
+  type: 1 # organization
+  salt: salt
+  is_admin: false
+  avatar: avatar6
+  avatar_email: user6@example.com
+  num_repos: 0
+  num_members: 1
+
+-
+  id: 7
+  lower_name: user7
+  name: user7
+  full_name: User Seven
+  email: user7@example.com
+  passwd: password
+  type: 1 # organization
+  salt: salt
+  is_admin: false
+  avatar: avatar7
+  avatar_email: user7@example.com
+  num_repos: 0
+  num_members: 1
diff --git a/models/org.go b/models/org.go
index 02f7bc4e7d..9911523b70 100644
--- a/models/org.go
+++ b/models/org.go
@@ -124,6 +124,7 @@ func CreateOrganization(org, owner *User) (err error) {
 	org.MaxRepoCreation = -1
 	org.NumTeams = 1
 	org.NumMembers = 1
+	org.Type = UserTypeOrganization
 
 	sess := x.NewSession()
 	defer sessionRelease(sess)
@@ -350,12 +351,6 @@ func GetOrgsByUserID(userID int64, showAll bool) ([]*User, error) {
 	return getOrgsByUserID(sess, userID, showAll)
 }
 
-// GetOrgsByUserIDDesc returns a list of organizations that the given user ID
-// has joined, ordered descending by the given condition.
-func GetOrgsByUserIDDesc(userID int64, desc string, showAll bool) ([]*User, error) {
-	return getOrgsByUserID(x.Desc(desc), userID, showAll)
-}
-
 func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
 	orgs := make([]*User, 0, 10)
 	return orgs, sess.
@@ -464,10 +459,6 @@ func RemoveOrgUser(orgID, userID int64) error {
 		return nil
 	}
 
-	user, err := GetUserByID(userID)
-	if err != nil {
-		return fmt.Errorf("GetUserByID [%d]: %v", userID, err)
-	}
 	org, err := GetUserByID(orgID)
 	if err != nil {
 		return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
@@ -497,23 +488,23 @@ func RemoveOrgUser(orgID, userID int64) error {
 	}
 
 	// Delete all repository accesses and unwatch them.
-	env, err := org.AccessibleReposEnv(user.ID)
+	env, err := org.AccessibleReposEnv(userID)
 	if err != nil {
 		return fmt.Errorf("AccessibleReposEnv: %v", err)
 	}
 	repoIDs, err := env.RepoIDs(1, org.NumRepos)
 	if err != nil {
-		return fmt.Errorf("GetUserRepositories [%d]: %v", user.ID, err)
+		return fmt.Errorf("GetUserRepositories [%d]: %v", userID, err)
 	}
 	for _, repoID := range repoIDs {
-		if err = watchRepo(sess, user.ID, repoID, false); err != nil {
+		if err = watchRepo(sess, userID, repoID, false); err != nil {
 			return err
 		}
 	}
 
 	if len(repoIDs) > 0 {
 		if _, err = sess.
-			Where("user_id = ?", user.ID).
+			Where("user_id = ?", userID).
 			In("repo_id", repoIDs).
 			Delete(new(Access)); err != nil {
 			return err
@@ -521,12 +512,12 @@ func RemoveOrgUser(orgID, userID int64) error {
 	}
 
 	// Delete member in his/her teams.
-	teams, err := getUserTeams(sess, org.ID, user.ID)
+	teams, err := getUserTeams(sess, org.ID, userID)
 	if err != nil {
 		return err
 	}
 	for _, t := range teams {
-		if err = removeTeamMember(sess, org.ID, t.ID, user.ID); err != nil {
+		if err = removeTeamMember(sess, org.ID, t.ID, userID); err != nil {
 			return err
 		}
 	}
@@ -542,11 +533,6 @@ func removeOrgRepo(e Engine, orgID, repoID int64) error {
 	return err
 }
 
-// RemoveOrgRepo removes all team-repository relations of given organization.
-func RemoveOrgRepo(orgID, repoID int64) error {
-	return removeOrgRepo(x, orgID, repoID)
-}
-
 func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team, error) {
 	teams := make([]*Team, 0, org.NumTeams)
 	return teams, e.
@@ -619,7 +605,7 @@ func (env *accessibleReposEnv) CountRepos() (int64, error) {
 	repoCount, err := x.
 		Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
 		Where(env.cond()).
-		GroupBy("`repository`.id").
+		Distinct("`repository`.id").
 		Count(&Repository{})
 	if err != nil {
 		return 0, fmt.Errorf("count user repositories in organization: %v", err)
diff --git a/models/org_test.go b/models/org_test.go
new file mode 100644
index 0000000000..bf505b0abb
--- /dev/null
+++ b/models/org_test.go
@@ -0,0 +1,520 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestUser_IsOwnedBy(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.True(t, org.IsOwnedBy(2))
+	assert.False(t, org.IsOwnedBy(1))
+	assert.False(t, org.IsOwnedBy(3))
+	assert.False(t, org.IsOwnedBy(4))
+
+	nonOrg := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	assert.False(t, nonOrg.IsOwnedBy(2))
+	assert.False(t, nonOrg.IsOwnedBy(3))
+}
+
+func TestUser_IsOrgMember(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.True(t, org.IsOrgMember(2))
+	assert.True(t, org.IsOrgMember(4))
+	assert.False(t, org.IsOrgMember(1))
+	assert.False(t, org.IsOrgMember(3))
+
+	nonOrg := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	assert.False(t, nonOrg.IsOrgMember(2))
+	assert.False(t, nonOrg.IsOrgMember(3))
+}
+
+func TestUser_GetTeam(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	team, err := org.GetTeam("team1")
+	assert.NoError(t, err)
+	assert.Equal(t, org.ID, team.OrgID)
+	assert.Equal(t, "team1", team.LowerName)
+
+	_, err = org.GetTeam("does not exist")
+	assert.Equal(t, ErrTeamNotExist, err)
+
+	nonOrg := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	_, err = nonOrg.GetTeam("team")
+	assert.Equal(t, ErrTeamNotExist, err)
+}
+
+func TestUser_GetOwnerTeam(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	team, err := org.GetOwnerTeam()
+	assert.NoError(t, err)
+	assert.Equal(t, org.ID, team.OrgID)
+
+	nonOrg := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	_, err = nonOrg.GetOwnerTeam()
+	assert.Equal(t, ErrTeamNotExist, err)
+}
+
+func TestUser_GetTeams(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.NoError(t, org.GetTeams())
+	assert.Len(t, org.Teams, 2)
+	assert.Equal(t, int64(1), org.Teams[0].ID)
+	assert.Equal(t, int64(2), org.Teams[1].ID)
+}
+
+func TestUser_GetMembers(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.NoError(t, org.GetMembers())
+	assert.Len(t, org.Members, 2)
+	assert.Equal(t, int64(2), org.Members[0].ID)
+	assert.Equal(t, int64(4), org.Members[1].ID)
+}
+
+func TestUser_AddMember(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+
+	// add a user that is not a member
+	AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
+	prevNumMembers := org.NumMembers
+	assert.NoError(t, org.AddMember(5))
+	AssertExistsAndLoadBean(t, &OrgUser{UID: 5, OrgID: 3})
+	org = AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.Equal(t, prevNumMembers+1, org.NumMembers)
+
+	// add a user that is already a member
+	AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
+	prevNumMembers = org.NumMembers
+	assert.NoError(t, org.AddMember(4))
+	AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
+	org = AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.Equal(t, prevNumMembers, org.NumMembers)
+}
+
+func TestUser_RemoveMember(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+
+	// remove a user that is a member
+	AssertExistsAndLoadBean(t, &OrgUser{UID: 4, OrgID: 3})
+	prevNumMembers := org.NumMembers
+	assert.NoError(t, org.RemoveMember(4))
+	AssertNotExistsBean(t, &OrgUser{UID: 4, OrgID: 3})
+	org = AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.Equal(t, prevNumMembers-1, org.NumMembers)
+
+	// remove a user that is not a member
+	AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
+	prevNumMembers = org.NumMembers
+	assert.NoError(t, org.RemoveMember(5))
+	AssertNotExistsBean(t, &OrgUser{UID: 5, OrgID: 3})
+	org = AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	assert.Equal(t, prevNumMembers, org.NumMembers)
+}
+
+func TestUser_RemoveOrgRepo(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	repo := AssertExistsAndLoadBean(t, &Repository{OwnerID: org.ID}).(*Repository)
+
+	// remove a repo that does belong to org
+	AssertExistsAndLoadBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
+	assert.NoError(t, org.RemoveOrgRepo(repo.ID))
+	AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
+	AssertExistsAndLoadBean(t, &Repository{ID: repo.ID}) // repo should still exist
+
+	// remove a repo that does not belong to org
+	assert.NoError(t, org.RemoveOrgRepo(repo.ID))
+	AssertNotExistsBean(t, &TeamRepo{RepoID: repo.ID, OrgID: org.ID})
+
+	assert.NoError(t, org.RemoveOrgRepo(NonexistentID))
+}
+
+func TestCreateOrganization(t *testing.T) {
+	// successful creation of org
+	assert.NoError(t, PrepareTestDatabase())
+
+	owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	const newOrgName = "neworg"
+	org := &User{
+		Name: newOrgName,
+	}
+
+	AssertNotExistsBean(t, &User{Name: newOrgName, Type: UserTypeOrganization})
+	assert.NoError(t, CreateOrganization(org, owner))
+	org = AssertExistsAndLoadBean(t,
+		&User{Name: newOrgName, Type: UserTypeOrganization}).(*User)
+	ownerTeam := AssertExistsAndLoadBean(t,
+		&Team{Name: ownerTeamName, OrgID: org.ID}).(*Team)
+	AssertExistsAndLoadBean(t, &TeamUser{UID: owner.ID, TeamID: ownerTeam.ID})
+}
+
+func TestCreateOrganization2(t *testing.T) {
+	// unauthorized creation of org
+	assert.NoError(t, PrepareTestDatabase())
+
+	owner := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+	const newOrgName = "neworg"
+	org := &User{
+		Name: newOrgName,
+	}
+
+	AssertNotExistsBean(t, &User{Name: newOrgName, Type: UserTypeOrganization})
+	err := CreateOrganization(org, owner)
+	assert.Error(t, err)
+	assert.True(t, IsErrUserNotAllowedCreateOrg(err))
+	AssertNotExistsBean(t, &User{Name: newOrgName, Type: UserTypeOrganization})
+}
+
+func TestCreateOrganization3(t *testing.T) {
+	// create org with same name as existent org
+	assert.NoError(t, PrepareTestDatabase())
+
+	owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	org := &User{Name: "user3"}                       // should already exist
+	AssertExistsAndLoadBean(t, &User{Name: org.Name}) // sanity check
+	err := CreateOrganization(org, owner)
+	assert.Error(t, err)
+	assert.True(t, IsErrUserAlreadyExist(err))
+}
+
+func TestCreateOrganization4(t *testing.T) {
+	// create org with unusable name
+	assert.NoError(t, PrepareTestDatabase())
+
+	owner := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+	err := CreateOrganization(&User{Name: "assets"}, owner)
+	assert.Error(t, err)
+	assert.True(t, IsErrNameReserved(err))
+}
+
+func TestGetOrgByName(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	org, err := GetOrgByName("user3")
+	assert.NoError(t, err)
+	assert.EqualValues(t, 3, org.ID)
+	assert.Equal(t, "user3", org.Name)
+
+	org, err = GetOrgByName("user2") // user2 is an individual
+	assert.Equal(t, ErrOrgNotExist, err)
+
+	org, err = GetOrgByName("") // corner case
+	assert.Equal(t, ErrOrgNotExist, err)
+}
+
+func TestCountOrganizations(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	expected, err := x.Where("type=?", UserTypeOrganization).Count(&User{})
+	assert.NoError(t, err)
+	assert.Equal(t, expected, CountOrganizations())
+}
+
+func TestOrganizations(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	testSuccess := func(opts *SearchUserOptions, expectedOrgIDs []int64) {
+		orgs, err := Organizations(opts)
+		assert.NoError(t, err)
+		assert.Len(t, orgs, len(expectedOrgIDs))
+		for i, expectedOrgID := range expectedOrgIDs {
+			assert.EqualValues(t, expectedOrgID, orgs[i].ID)
+		}
+	}
+	testSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 1, PageSize: 2},
+		[]int64{3, 6})
+
+	testSuccess(&SearchUserOptions{OrderBy: "id ASC", Page: 2, PageSize: 2},
+		[]int64{7})
+
+	testSuccess(&SearchUserOptions{Page: 3, PageSize: 2},
+		[]int64{})
+}
+
+func TestDeleteOrganization(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 6}).(*User)
+	assert.NoError(t, DeleteOrganization(org))
+	AssertNotExistsBean(t, &User{ID: 6})
+	AssertNotExistsBean(t, &OrgUser{OrgID: 6})
+	AssertNotExistsBean(t, &Team{OrgID: 6})
+
+	org = AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	err := DeleteOrganization(org)
+	assert.Error(t, err)
+	assert.True(t, IsErrUserOwnRepos(err))
+
+	nonOrg := AssertExistsAndLoadBean(t, &User{ID: 5}).(*User)
+	assert.Error(t, DeleteOrganization(nonOrg))
+}
+
+func TestIsOrganizationOwner(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	assert.True(t, IsOrganizationOwner(3, 2))
+	assert.False(t, IsOrganizationOwner(3, 3))
+	assert.True(t, IsOrganizationOwner(6, 5))
+	assert.False(t, IsOrganizationOwner(6, 4))
+	assert.False(t, IsOrganizationOwner(NonexistentID, NonexistentID))
+}
+
+func TestIsOrganizationMember(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	assert.True(t, IsOrganizationMember(3, 2))
+	assert.False(t, IsOrganizationMember(3, 3))
+	assert.True(t, IsOrganizationMember(3, 4))
+	assert.True(t, IsOrganizationMember(6, 5))
+	assert.False(t, IsOrganizationMember(6, 4))
+	assert.False(t, IsOrganizationMember(NonexistentID, NonexistentID))
+}
+
+func TestIsPublicMembership(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	assert.True(t, IsPublicMembership(3, 2))
+	assert.False(t, IsPublicMembership(3, 3))
+	assert.False(t, IsPublicMembership(3, 4))
+	assert.True(t, IsPublicMembership(6, 5))
+	assert.False(t, IsPublicMembership(6, 4))
+	assert.False(t, IsPublicMembership(NonexistentID, NonexistentID))
+}
+
+func TestGetOrgsByUserID(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	orgs, err := GetOrgsByUserID(4, true)
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 1)
+	assert.EqualValues(t, 3, orgs[0].ID)
+
+	orgs, err = GetOrgsByUserID(4, false)
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 0)
+}
+
+func TestGetOwnedOrgsByUserID(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	orgs, err := GetOwnedOrgsByUserID(2)
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 1)
+	assert.EqualValues(t, 3, orgs[0].ID)
+
+	orgs, err = GetOwnedOrgsByUserID(4)
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 0)
+}
+
+func TestGetOwnedOrgsByUserIDDesc(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	orgs, err := GetOwnedOrgsByUserIDDesc(5, "id")
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 2)
+	assert.EqualValues(t, 7, orgs[0].ID)
+	assert.EqualValues(t, 6, orgs[1].ID)
+
+	orgs, err = GetOwnedOrgsByUserIDDesc(4, "id")
+	assert.NoError(t, err)
+	assert.Len(t, orgs, 0)
+}
+
+func TestGetOrgUsersByUserID(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	orgUsers, err := GetOrgUsersByUserID(5, true)
+	assert.NoError(t, err)
+	assert.Len(t, orgUsers, 2)
+	assert.Equal(t, OrgUser{
+		ID:       orgUsers[0].ID,
+		OrgID:    6,
+		UID:      5,
+		IsOwner:  true,
+		IsPublic: true,
+		NumTeams: 1}, *orgUsers[0])
+	assert.Equal(t, OrgUser{
+		ID:       orgUsers[1].ID,
+		OrgID:    7,
+		UID:      5,
+		IsOwner:  true,
+		IsPublic: false,
+		NumTeams: 1}, *orgUsers[1])
+
+	publicOrgUsers, err := GetOrgUsersByUserID(5, false)
+	assert.NoError(t, err)
+	assert.Len(t, publicOrgUsers, 1)
+	assert.Equal(t, *orgUsers[0], *publicOrgUsers[0])
+
+	orgUsers, err = GetOrgUsersByUserID(1, true)
+	assert.NoError(t, err)
+	assert.Len(t, orgUsers, 0)
+}
+
+func TestGetOrgUsersByOrgID(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	orgUsers, err := GetOrgUsersByOrgID(3)
+	assert.NoError(t, err)
+	assert.Len(t, orgUsers, 2)
+	assert.Equal(t, OrgUser{
+		ID:       orgUsers[0].ID,
+		OrgID:    3,
+		UID:      2,
+		IsOwner:  true,
+		IsPublic: true,
+		NumTeams: 1}, *orgUsers[0])
+	assert.Equal(t, OrgUser{
+		ID:       orgUsers[1].ID,
+		OrgID:    3,
+		UID:      4,
+		IsOwner:  false,
+		IsPublic: false,
+		NumTeams: 0}, *orgUsers[1])
+
+	orgUsers, err = GetOrgUsersByOrgID(NonexistentID)
+	assert.NoError(t, err)
+	assert.Len(t, orgUsers, 0)
+}
+
+func TestChangeOrgUserStatus(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+
+	testSuccess := func(orgID, userID int64, public bool) {
+		assert.NoError(t, ChangeOrgUserStatus(orgID, userID, public))
+		orgUser := AssertExistsAndLoadBean(t, &OrgUser{OrgID: orgID, UID: userID}).(*OrgUser)
+		assert.Equal(t, public, orgUser.IsPublic)
+	}
+
+	testSuccess(3, 2, false)
+	testSuccess(3, 2, false)
+	testSuccess(3, 4, true)
+	assert.NoError(t, ChangeOrgUserStatus(NonexistentID, NonexistentID, true))
+}
+
+func TestAddOrgUser(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	testSuccess := func(orgID, userID int64) {
+		org := AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+		expectedNumMembers := org.NumMembers
+		if !BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
+			expectedNumMembers++
+		}
+		assert.NoError(t, AddOrgUser(orgID, userID))
+		AssertExistsAndLoadBean(t, &OrgUser{OrgID: orgID, UID: userID})
+		org = AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+		assert.EqualValues(t, expectedNumMembers, org.NumMembers)
+	}
+	testSuccess(3, 5)
+	testSuccess(3, 5)
+	testSuccess(6, 2)
+}
+
+func TestRemoveOrgUser(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	testSuccess := func(orgID, userID int64) {
+		org := AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+		expectedNumMembers := org.NumMembers
+		if BeanExists(t, &OrgUser{OrgID: orgID, UID: userID}) {
+			expectedNumMembers--
+		}
+		assert.NoError(t, RemoveOrgUser(orgID, userID))
+		AssertNotExistsBean(t, &OrgUser{OrgID: orgID, UID: userID})
+		org = AssertExistsAndLoadBean(t, &User{ID: orgID}).(*User)
+		assert.EqualValues(t, expectedNumMembers, org.NumMembers)
+	}
+	testSuccess(3, 4)
+	testSuccess(3, 4)
+
+	err := RemoveOrgUser(7, 5)
+	assert.Error(t, err)
+	assert.True(t, IsErrLastOrgOwner(err))
+	AssertExistsAndLoadBean(t, &OrgUser{OrgID: 7, UID: 5})
+}
+
+func TestUser_GetUserTeamIDs(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	testSuccess := func(userID int64, expected []int64) {
+		teamIDs, err := org.GetUserTeamIDs(userID)
+		assert.NoError(t, err)
+		assert.Equal(t, expected, teamIDs)
+	}
+	testSuccess(2, []int64{1, 2})
+	testSuccess(4, []int64{2})
+	testSuccess(NonexistentID, []int64{})
+}
+
+func TestAccessibleReposEnv_CountRepos(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	testSuccess := func(userID, expectedCount int64) {
+		env, err := org.AccessibleReposEnv(userID)
+		assert.NoError(t, err)
+		count, err := env.CountRepos()
+		assert.NoError(t, err)
+		assert.EqualValues(t, expectedCount, count)
+	}
+	testSuccess(2, 2)
+	testSuccess(4, 1)
+}
+
+func TestAccessibleReposEnv_RepoIDs(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	testSuccess := func(userID, page, pageSize int64, expectedRepoIDs []int64) {
+		env, err := org.AccessibleReposEnv(userID)
+		assert.NoError(t, err)
+		repoIDs, err := env.RepoIDs(1, 100)
+		assert.NoError(t, err)
+		assert.Equal(t, expectedRepoIDs, repoIDs)
+	}
+	testSuccess(2, 1, 100, []int64{3, 5})
+	testSuccess(4, 0, 100, []int64{3})
+}
+
+func TestAccessibleReposEnv_Repos(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	testSuccess := func(userID int64, expectedRepoIDs []int64) {
+		env, err := org.AccessibleReposEnv(userID)
+		assert.NoError(t, err)
+		repos, err := env.Repos(1, 100)
+		assert.NoError(t, err)
+		expectedRepos := make([]*Repository, len(expectedRepoIDs))
+		for i, repoID := range expectedRepoIDs {
+			expectedRepos[i] = AssertExistsAndLoadBean(t,
+				&Repository{ID: repoID}).(*Repository)
+		}
+		assert.Equal(t, expectedRepos, repos)
+	}
+	testSuccess(2, []int64{3, 5})
+	testSuccess(4, []int64{3})
+}
+
+func TestAccessibleReposEnv_MirrorRepos(t *testing.T) {
+	assert.NoError(t, PrepareTestDatabase())
+	org := AssertExistsAndLoadBean(t, &User{ID: 3}).(*User)
+	testSuccess := func(userID int64, expectedRepoIDs []int64) {
+		env, err := org.AccessibleReposEnv(userID)
+		assert.NoError(t, err)
+		repos, err := env.MirrorRepos()
+		assert.NoError(t, err)
+		expectedRepos := make([]*Repository, len(expectedRepoIDs))
+		for i, repoID := range expectedRepoIDs {
+			expectedRepos[i] = AssertExistsAndLoadBean(t,
+				&Repository{ID: repoID}).(*Repository)
+		}
+		assert.Equal(t, expectedRepos, repos)
+	}
+	testSuccess(2, []int64{5})
+	testSuccess(4, []int64{})
+}
diff --git a/models/setup_for_test.go b/models/setup_for_test.go
index 058436ca66..aec409622b 100644
--- a/models/setup_for_test.go
+++ b/models/setup_for_test.go
@@ -59,6 +59,13 @@ func loadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error)
 	return sess.Get(bean)
 }
 
+// BeanExists for testing, check if a bean exists
+func BeanExists(t *testing.T, bean interface{}, conditions ...interface{}) bool {
+	exists, err := loadBeanIfExists(bean, conditions...)
+	assert.NoError(t, err)
+	return exists
+}
+
 // AssertExistsAndLoadBean assert that a bean exists and load it from the test
 // database
 func AssertExistsAndLoadBean(t *testing.T, bean interface{}, conditions ...interface{}) interface{} {