2017-02-23 04:36:15 +03:00
// 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 (
"strings"
"testing"
2021-11-24 12:49:20 +03:00
"code.gitea.io/gitea/models/db"
2021-11-12 17:36:47 +03:00
"code.gitea.io/gitea/models/unittest"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2021-11-17 15:34:35 +03:00
2017-02-23 04:36:15 +03:00
"github.com/stretchr/testify/assert"
)
func TestTeam_IsOwnerTeam ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 1 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . True ( t , team . IsOwnerTeam ( ) )
2021-11-16 11:53:21 +03:00
team = unittest . AssertExistsAndLoadBean ( t , & Team { ID : 2 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . False ( t , team . IsOwnerTeam ( ) )
}
func TestTeam_IsMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 1 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . True ( t , team . IsMember ( 2 ) )
assert . False ( t , team . IsMember ( 4 ) )
2021-11-16 11:53:21 +03:00
assert . False ( t , team . IsMember ( unittest . NonexistentID ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team = unittest . AssertExistsAndLoadBean ( t , & Team { ID : 2 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . True ( t , team . IsMember ( 2 ) )
assert . True ( t , team . IsMember ( 4 ) )
2021-11-16 11:53:21 +03:00
assert . False ( t , team . IsMember ( unittest . NonexistentID ) )
2017-02-23 04:36:15 +03:00
}
func TestTeam_GetRepositories ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2020-01-24 22:00:29 +03:00
assert . NoError ( t , team . GetRepositories ( & SearchTeamOptions { } ) )
2017-02-23 04:36:15 +03:00
assert . Len ( t , team . Repos , team . NumRepos )
for _ , repo := range team . Repos {
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamRepo { TeamID : teamID , RepoID : repo . ID } )
2017-02-23 04:36:15 +03:00
}
}
test ( 1 )
test ( 3 )
}
func TestTeam_GetMembers ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2020-01-24 22:00:29 +03:00
assert . NoError ( t , team . GetMembers ( & SearchMembersOptions { } ) )
2017-02-23 04:36:15 +03:00
assert . Len ( t , team . Members , team . NumMembers )
for _ , member := range team . Members {
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { UID : member . ID , TeamID : teamID } )
2017-02-23 04:36:15 +03:00
}
}
test ( 1 )
test ( 3 )
}
func TestTeam_AddMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID , userID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , team . AddMember ( userID ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { UID : userID , TeamID : teamID } )
2021-11-24 12:49:20 +03:00
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } , & user_model . User { ID : team . OrgID } )
2017-02-23 04:36:15 +03:00
}
test ( 1 , 2 )
test ( 1 , 4 )
test ( 3 , 2 )
}
func TestTeam_RemoveMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
testSuccess := func ( teamID , userID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , team . RemoveMember ( userID ) )
2021-11-16 11:53:21 +03:00
unittest . AssertNotExistsBean ( t , & TeamUser { UID : userID , TeamID : teamID } )
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } )
2017-02-23 04:36:15 +03:00
}
testSuccess ( 1 , 4 )
testSuccess ( 2 , 2 )
testSuccess ( 3 , 2 )
2021-11-16 11:53:21 +03:00
testSuccess ( 3 , unittest . NonexistentID )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 1 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
err := team . RemoveMember ( 2 )
assert . True ( t , IsErrLastOrgOwner ( err ) )
}
func TestTeam_HasRepository ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID , repoID int64 , expected bool ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . Equal ( t , expected , team . HasRepository ( repoID ) )
}
test ( 1 , 1 , false )
test ( 1 , 3 , true )
test ( 1 , 5 , true )
2021-11-16 11:53:21 +03:00
test ( 1 , unittest . NonexistentID , false )
2017-02-23 04:36:15 +03:00
test ( 2 , 3 , true )
test ( 2 , 5 , false )
}
func TestTeam_AddRepository ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2017-03-15 03:52:01 +03:00
testSuccess := func ( teamID , repoID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
repo := unittest . AssertExistsAndLoadBean ( t , & Repository { ID : repoID } ) . ( * Repository )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , team . AddRepository ( repo ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamRepo { TeamID : teamID , RepoID : repoID } )
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } , & Repository { ID : repoID } )
2017-02-23 04:36:15 +03:00
}
2017-03-15 03:52:01 +03:00
testSuccess ( 2 , 3 )
testSuccess ( 2 , 5 )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 1 } ) . ( * Team )
repo := unittest . AssertExistsAndLoadBean ( t , & Repository { ID : 1 } ) . ( * Repository )
2017-02-23 04:36:15 +03:00
assert . Error ( t , team . AddRepository ( repo ) )
2021-11-16 11:53:21 +03:00
unittest . CheckConsistencyFor ( t , & Team { ID : 1 } , & Repository { ID : 1 } )
2017-02-23 04:36:15 +03:00
}
func TestTeam_RemoveRepository ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
testSuccess := func ( teamID , repoID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , team . RemoveRepository ( repoID ) )
2021-11-16 11:53:21 +03:00
unittest . AssertNotExistsBean ( t , & TeamRepo { TeamID : teamID , RepoID : repoID } )
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } , & Repository { ID : repoID } )
2017-02-23 04:36:15 +03:00
}
testSuccess ( 2 , 3 )
testSuccess ( 2 , 5 )
2021-11-16 11:53:21 +03:00
testSuccess ( 1 , unittest . NonexistentID )
2017-02-23 04:36:15 +03:00
}
func TestIsUsableTeamName ( t * testing . T ) {
assert . NoError ( t , IsUsableTeamName ( "usable" ) )
2021-11-24 12:49:20 +03:00
assert . True ( t , db . IsErrNameReserved ( IsUsableTeamName ( "new" ) ) )
2017-02-23 04:36:15 +03:00
}
func TestNewTeam ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
const teamName = "newTeamName"
team := & Team { Name : teamName , OrgID : 3 }
assert . NoError ( t , NewTeam ( team ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & Team { Name : teamName } )
2021-11-24 12:49:20 +03:00
unittest . CheckConsistencyFor ( t , & Team { } , & user_model . User { ID : team . OrgID } )
2017-02-23 04:36:15 +03:00
}
func TestGetTeam ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
testSuccess := func ( orgID int64 , name string ) {
team , err := GetTeam ( orgID , name )
assert . NoError ( t , err )
assert . EqualValues ( t , orgID , team . OrgID )
assert . Equal ( t , name , team . Name )
}
testSuccess ( 3 , "Owners" )
testSuccess ( 3 , "team1" )
_ , err := GetTeam ( 3 , "nonexistent" )
assert . Error ( t , err )
2021-11-16 11:53:21 +03:00
_ , err = GetTeam ( unittest . NonexistentID , "Owners" )
2017-02-23 04:36:15 +03:00
assert . Error ( t , err )
}
func TestGetTeamByID ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
testSuccess := func ( teamID int64 ) {
team , err := GetTeamByID ( teamID )
assert . NoError ( t , err )
assert . EqualValues ( t , teamID , team . ID )
}
testSuccess ( 1 )
testSuccess ( 2 )
testSuccess ( 3 )
testSuccess ( 4 )
2021-11-16 11:53:21 +03:00
_ , err := GetTeamByID ( unittest . NonexistentID )
2017-02-23 04:36:15 +03:00
assert . Error ( t , err )
}
func TestUpdateTeam ( t * testing . T ) {
// successful update
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 2 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
team . LowerName = "newname"
team . Name = "newName"
team . Description = strings . Repeat ( "A long description!" , 100 )
team . Authorize = AccessModeAdmin
2019-11-06 12:37:14 +03:00
assert . NoError ( t , UpdateTeam ( team , true , false ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team = unittest . AssertExistsAndLoadBean ( t , & Team { Name : "newName" } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . True ( t , strings . HasPrefix ( team . Description , "A long description!" ) )
2021-11-16 11:53:21 +03:00
access := unittest . AssertExistsAndLoadBean ( t , & Access { UserID : 4 , RepoID : 3 } ) . ( * Access )
2017-02-23 04:36:15 +03:00
assert . EqualValues ( t , AccessModeAdmin , access . Mode )
2021-11-16 11:53:21 +03:00
unittest . CheckConsistencyFor ( t , & Team { ID : team . ID } )
2017-02-23 04:36:15 +03:00
}
func TestUpdateTeam2 ( t * testing . T ) {
// update to already-existing team
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 2 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
team . LowerName = "owners"
team . Name = "Owners"
team . Description = strings . Repeat ( "A long description!" , 100 )
2019-11-06 12:37:14 +03:00
err := UpdateTeam ( team , true , false )
2017-02-23 04:36:15 +03:00
assert . True ( t , IsErrTeamAlreadyExist ( err ) )
2021-11-16 11:53:21 +03:00
unittest . CheckConsistencyFor ( t , & Team { ID : team . ID } )
2017-02-23 04:36:15 +03:00
}
func TestDeleteTeam ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 2 } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , DeleteTeam ( team ) )
2021-11-16 11:53:21 +03:00
unittest . AssertNotExistsBean ( t , & Team { ID : team . ID } )
unittest . AssertNotExistsBean ( t , & TeamRepo { TeamID : team . ID } )
unittest . AssertNotExistsBean ( t , & TeamUser { TeamID : team . ID } )
2017-02-23 04:36:15 +03:00
// check that team members don't have "leftover" access to repos
2021-11-24 12:49:20 +03:00
user := unittest . AssertExistsAndLoadBean ( t , & user_model . User { ID : 4 } ) . ( * user_model . User )
2021-11-16 11:53:21 +03:00
repo := unittest . AssertExistsAndLoadBean ( t , & Repository { ID : 3 } ) . ( * Repository )
2018-11-28 14:26:14 +03:00
accessMode , err := AccessLevel ( user , repo )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , err )
assert . True ( t , accessMode < AccessModeWrite )
}
func TestIsTeamMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-12-21 10:43:26 +03:00
test := func ( orgID , teamID , userID int64 , expected bool ) {
isMember , err := IsTeamMember ( orgID , teamID , userID )
assert . NoError ( t , err )
assert . Equal ( t , expected , isMember )
}
2017-02-23 04:36:15 +03:00
2017-12-21 10:43:26 +03:00
test ( 3 , 1 , 2 , true )
test ( 3 , 1 , 4 , false )
2021-11-16 11:53:21 +03:00
test ( 3 , 1 , unittest . NonexistentID , false )
2017-02-23 04:36:15 +03:00
2017-12-21 10:43:26 +03:00
test ( 3 , 2 , 2 , true )
test ( 3 , 2 , 4 , true )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
test ( 3 , unittest . NonexistentID , unittest . NonexistentID , false )
test ( unittest . NonexistentID , unittest . NonexistentID , unittest . NonexistentID , false )
2017-02-23 04:36:15 +03:00
}
func TestGetTeamMembers ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
members , err := GetTeamMembers ( teamID )
assert . NoError ( t , err )
assert . Len ( t , members , team . NumMembers )
for _ , member := range members {
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { UID : member . ID , TeamID : teamID } )
2017-02-23 04:36:15 +03:00
}
}
test ( 1 )
test ( 3 )
}
func TestGetUserTeams ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2019-01-17 03:39:50 +03:00
test := func ( userID int64 ) {
2021-08-12 15:43:08 +03:00
teams , _ , err := SearchTeam ( & SearchTeamOptions { UserID : userID } )
2019-01-17 03:39:50 +03:00
assert . NoError ( t , err )
for _ , team := range teams {
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { TeamID : team . ID , UID : userID } )
2019-01-17 03:39:50 +03:00
}
}
test ( 2 )
test ( 5 )
2021-11-16 11:53:21 +03:00
test ( unittest . NonexistentID )
2019-01-17 03:39:50 +03:00
}
func TestGetUserOrgTeams ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( orgID , userID int64 ) {
2019-01-17 03:39:50 +03:00
teams , err := GetUserOrgTeams ( orgID , userID )
2017-02-23 04:36:15 +03:00
assert . NoError ( t , err )
for _ , team := range teams {
assert . EqualValues ( t , orgID , team . OrgID )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { TeamID : team . ID , UID : userID } )
2017-02-23 04:36:15 +03:00
}
}
test ( 3 , 2 )
test ( 3 , 4 )
2021-11-16 11:53:21 +03:00
test ( 3 , unittest . NonexistentID )
2017-02-23 04:36:15 +03:00
}
func TestAddTeamMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID , userID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-24 09:25:09 +03:00
assert . NoError ( t , AddTeamMember ( team , userID ) )
2021-11-16 11:53:21 +03:00
unittest . AssertExistsAndLoadBean ( t , & TeamUser { UID : userID , TeamID : teamID } )
2021-11-24 12:49:20 +03:00
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } , & user_model . User { ID : team . OrgID } )
2017-02-23 04:36:15 +03:00
}
test ( 1 , 2 )
test ( 1 , 4 )
test ( 3 , 2 )
}
func TestRemoveTeamMember ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
testSuccess := func ( teamID , userID int64 ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-24 09:25:09 +03:00
assert . NoError ( t , RemoveTeamMember ( team , userID ) )
2021-11-16 11:53:21 +03:00
unittest . AssertNotExistsBean ( t , & TeamUser { UID : userID , TeamID : teamID } )
unittest . CheckConsistencyFor ( t , & Team { ID : teamID } )
2017-02-23 04:36:15 +03:00
}
testSuccess ( 1 , 4 )
testSuccess ( 2 , 2 )
testSuccess ( 3 , 2 )
2021-11-16 11:53:21 +03:00
testSuccess ( 3 , unittest . NonexistentID )
2017-02-23 04:36:15 +03:00
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : 1 } ) . ( * Team )
2017-02-24 09:25:09 +03:00
err := RemoveTeamMember ( team , 2 )
2017-02-23 04:36:15 +03:00
assert . True ( t , IsErrLastOrgOwner ( err ) )
}
func TestHasTeamRepo ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2017-02-23 04:36:15 +03:00
test := func ( teamID , repoID int64 , expected bool ) {
2021-11-16 11:53:21 +03:00
team := unittest . AssertExistsAndLoadBean ( t , & Team { ID : teamID } ) . ( * Team )
2017-02-23 04:36:15 +03:00
assert . Equal ( t , expected , HasTeamRepo ( team . OrgID , teamID , repoID ) )
}
test ( 1 , 1 , false )
test ( 1 , 3 , true )
test ( 1 , 5 , true )
2021-11-16 11:53:21 +03:00
test ( 1 , unittest . NonexistentID , false )
2017-02-23 04:36:15 +03:00
test ( 2 , 3 , true )
test ( 2 , 5 , false )
}
2018-12-11 14:28:37 +03:00
func TestUsersInTeamsCount ( t * testing . T ) {
2021-11-12 17:36:47 +03:00
assert . NoError ( t , unittest . PrepareTestDatabase ( ) )
2018-12-11 14:28:37 +03:00
2021-03-14 21:52:12 +03:00
test := func ( teamIDs , userIDs [ ] int64 , expected int64 ) {
2018-12-11 14:28:37 +03:00
count , err := UsersInTeamsCount ( teamIDs , userIDs )
assert . NoError ( t , err )
assert . Equal ( t , expected , count )
}
2019-08-07 07:22:41 +03:00
test ( [ ] int64 { 2 } , [ ] int64 { 1 , 2 , 3 , 4 } , 1 ) // only userid 2
test ( [ ] int64 { 1 , 2 , 3 , 4 , 5 } , [ ] int64 { 2 , 5 } , 2 ) // userid 2,4
test ( [ ] int64 { 1 , 2 , 3 , 4 , 5 } , [ ] int64 { 2 , 3 , 5 } , 3 ) // userid 2,4,5
2018-12-11 14:28:37 +03:00
}