2017-01-09 06:08:36 +03:00
package models
import (
2017-05-26 04:38:18 +03:00
"path"
2017-02-28 04:42:10 +03:00
"strings"
2017-01-09 06:08:36 +03:00
"testing"
"code.gitea.io/gitea/modules/setting"
2017-02-28 04:42:10 +03:00
2017-01-09 06:08:36 +03:00
"github.com/stretchr/testify/assert"
)
func TestAction_GetRepoPath ( t * testing . T ) {
2017-05-26 04:38:18 +03:00
assert . NoError ( t , PrepareTestDatabase ( ) )
repo := AssertExistsAndLoadBean ( t , & Repository { } ) . ( * Repository )
owner := AssertExistsAndLoadBean ( t , & User { ID : repo . OwnerID } ) . ( * User )
action := & Action { RepoID : repo . ID }
assert . Equal ( t , path . Join ( owner . Name , repo . Name ) , action . GetRepoPath ( ) )
2017-01-09 06:08:36 +03:00
}
func TestAction_GetRepoLink ( t * testing . T ) {
2017-05-26 04:38:18 +03:00
assert . NoError ( t , PrepareTestDatabase ( ) )
repo := AssertExistsAndLoadBean ( t , & Repository { } ) . ( * Repository )
owner := AssertExistsAndLoadBean ( t , & User { ID : repo . OwnerID } ) . ( * User )
action := & Action { RepoID : repo . ID }
2017-01-09 06:08:36 +03:00
setting . AppSubURL = "/suburl/"
2017-05-26 04:38:18 +03:00
expected := path . Join ( setting . AppSubURL , owner . Name , repo . Name )
assert . Equal ( t , expected , action . GetRepoLink ( ) )
2017-01-09 06:08:36 +03:00
}
func TestNewRepoAction ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-01-25 05:49:51 +03:00
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { OwnerID : user . ID } ) . ( * Repository )
2017-01-09 06:08:36 +03:00
repo . Owner = user
actionBean := & Action {
2017-05-26 04:38:18 +03:00
OpType : ActionCreateRepo ,
ActUserID : user . ID ,
RepoID : repo . ID ,
ActUser : user ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
2017-01-09 06:08:36 +03:00
}
AssertNotExistsBean ( t , actionBean )
assert . NoError ( t , NewRepoAction ( user , repo ) )
AssertExistsAndLoadBean ( t , actionBean )
2017-02-28 04:42:10 +03:00
CheckConsistencyFor ( t , & Action { } )
2017-01-09 06:08:36 +03:00
}
func TestRenameRepoAction ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-01-25 05:49:51 +03:00
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { OwnerID : user . ID } ) . ( * Repository )
2017-01-09 06:08:36 +03:00
repo . Owner = user
oldRepoName := repo . Name
const newRepoName = "newRepoName"
repo . Name = newRepoName
2017-02-28 04:42:10 +03:00
repo . LowerName = strings . ToLower ( newRepoName )
2017-01-09 06:08:36 +03:00
actionBean := & Action {
2017-05-26 04:38:18 +03:00
OpType : ActionRenameRepo ,
ActUserID : user . ID ,
ActUser : user ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
Content : oldRepoName ,
2017-01-09 06:08:36 +03:00
}
AssertNotExistsBean ( t , actionBean )
assert . NoError ( t , RenameRepoAction ( user , oldRepoName , repo ) )
AssertExistsAndLoadBean ( t , actionBean )
2017-02-28 04:42:10 +03:00
2017-10-05 07:43:04 +03:00
_ , err := x . ID ( repo . ID ) . Cols ( "name" , "lower_name" ) . Update ( repo )
2017-02-28 04:42:10 +03:00
assert . NoError ( t , err )
CheckConsistencyFor ( t , & Action { } )
2017-01-09 06:08:36 +03:00
}
func TestPushCommits_ToAPIPayloadCommits ( t * testing . T ) {
pushCommits := NewPushCommits ( )
pushCommits . Commits = [ ] * PushCommit {
{
2019-08-21 08:16:22 +03:00
Sha1 : "69554a6" ,
2017-01-09 06:08:36 +03:00
CommitterEmail : "user2@example.com" ,
2019-08-21 08:16:22 +03:00
CommitterName : "User2" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User2" ,
Message : "not signed commit" ,
2017-01-09 06:08:36 +03:00
} ,
{
2019-08-21 08:16:22 +03:00
Sha1 : "27566bd" ,
2017-01-09 06:08:36 +03:00
CommitterEmail : "user2@example.com" ,
2019-08-21 08:16:22 +03:00
CommitterName : "User2" ,
2017-01-09 06:08:36 +03:00
AuthorEmail : "user2@example.com" ,
2019-08-21 08:16:22 +03:00
AuthorName : "User2" ,
Message : "good signed commit (with not yet validated email)" ,
} ,
{
Sha1 : "5099b81" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User2" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User2" ,
Message : "good signed commit" ,
2017-01-09 06:08:36 +03:00
} ,
}
pushCommits . Len = len ( pushCommits . Commits )
2019-08-21 08:16:22 +03:00
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 16 } ) . ( * Repository )
payloadCommits , err := pushCommits . ToAPIPayloadCommits ( repo . RepoPath ( ) , "/user2/repo16" )
assert . NoError ( t , err )
assert . EqualValues ( t , 3 , len ( payloadCommits ) )
assert . Equal ( t , "69554a6" , payloadCommits [ 0 ] . ID )
assert . Equal ( t , "not signed commit" , payloadCommits [ 0 ] . Message )
assert . Equal ( t , "/user2/repo16/commit/69554a6" , payloadCommits [ 0 ] . URL )
assert . Equal ( t , "User2" , payloadCommits [ 0 ] . Committer . Name )
assert . Equal ( t , "user2" , payloadCommits [ 0 ] . Committer . UserName )
assert . Equal ( t , "User2" , payloadCommits [ 0 ] . Author . Name )
assert . Equal ( t , "user2" , payloadCommits [ 0 ] . Author . UserName )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 0 ] . Added )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 0 ] . Removed )
assert . EqualValues ( t , [ ] string { "readme.md" } , payloadCommits [ 0 ] . Modified )
assert . Equal ( t , "27566bd" , payloadCommits [ 1 ] . ID )
assert . Equal ( t , "good signed commit (with not yet validated email)" , payloadCommits [ 1 ] . Message )
assert . Equal ( t , "/user2/repo16/commit/27566bd" , payloadCommits [ 1 ] . URL )
assert . Equal ( t , "User2" , payloadCommits [ 1 ] . Committer . Name )
assert . Equal ( t , "user2" , payloadCommits [ 1 ] . Committer . UserName )
assert . Equal ( t , "User2" , payloadCommits [ 1 ] . Author . Name )
assert . Equal ( t , "user2" , payloadCommits [ 1 ] . Author . UserName )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 1 ] . Added )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 1 ] . Removed )
assert . EqualValues ( t , [ ] string { "readme.md" } , payloadCommits [ 1 ] . Modified )
assert . Equal ( t , "5099b81" , payloadCommits [ 2 ] . ID )
assert . Equal ( t , "good signed commit" , payloadCommits [ 2 ] . Message )
assert . Equal ( t , "/user2/repo16/commit/5099b81" , payloadCommits [ 2 ] . URL )
assert . Equal ( t , "User2" , payloadCommits [ 2 ] . Committer . Name )
assert . Equal ( t , "user2" , payloadCommits [ 2 ] . Committer . UserName )
assert . Equal ( t , "User2" , payloadCommits [ 2 ] . Author . Name )
assert . Equal ( t , "user2" , payloadCommits [ 2 ] . Author . UserName )
assert . EqualValues ( t , [ ] string { "readme.md" } , payloadCommits [ 2 ] . Added )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 2 ] . Removed )
assert . EqualValues ( t , [ ] string { } , payloadCommits [ 2 ] . Modified )
2017-01-09 06:08:36 +03:00
}
func TestPushCommits_AvatarLink ( t * testing . T ) {
pushCommits := NewPushCommits ( )
pushCommits . Commits = [ ] * PushCommit {
{
Sha1 : "abcdef1" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user4@example.com" ,
AuthorName : "User Four" ,
Message : "message1" ,
} ,
{
Sha1 : "abcdef2" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User Two" ,
Message : "message2" ,
} ,
}
pushCommits . Len = len ( pushCommits . Commits )
assert . Equal ( t ,
2019-09-26 19:21:23 +03:00
"/suburl/user/avatar/user2/-1" ,
2017-01-09 06:08:36 +03:00
pushCommits . AvatarLink ( "user2@example.com" ) )
assert . Equal ( t ,
2017-10-23 11:50:07 +03:00
"https://secure.gravatar.com/avatar/19ade630b94e1e0535b3df7387434154?d=identicon" ,
2017-01-09 06:08:36 +03:00
pushCommits . AvatarLink ( "nonexistent@example.com" ) )
}
func TestUpdateIssuesCommit ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
pushCommits := [ ] * PushCommit {
{
Sha1 : "abcdef1" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user4@example.com" ,
AuthorName : "User Four" ,
2017-07-13 06:35:47 +03:00
Message : "start working on #FST-1, #1" ,
2017-01-09 06:08:36 +03:00
} ,
{
Sha1 : "abcdef2" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User Two" ,
Message : "a plain message" ,
} ,
{
Sha1 : "abcdef2" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User Two" ,
Message : "close #2" ,
} ,
}
2017-01-25 05:49:51 +03:00
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 1 } ) . ( * Repository )
2017-01-09 06:08:36 +03:00
repo . Owner = user
commentBean := & Comment {
Type : CommentTypeCommitRef ,
CommitSHA : "abcdef1" ,
PosterID : user . ID ,
IssueID : 1 ,
}
issueBean := & Issue { RepoID : repo . ID , Index : 2 }
AssertNotExistsBean ( t , commentBean )
AssertNotExistsBean ( t , & Issue { RepoID : repo . ID , Index : 2 } , "is_closed=1" )
2019-01-04 12:22:58 +03:00
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , repo . DefaultBranch ) )
2017-01-09 06:08:36 +03:00
AssertExistsAndLoadBean ( t , commentBean )
AssertExistsAndLoadBean ( t , issueBean , "is_closed=1" )
2017-02-28 04:42:10 +03:00
CheckConsistencyFor ( t , & Action { } )
2019-01-04 12:22:58 +03:00
// Test that push to a non-default branch closes no issue.
pushCommits = [ ] * PushCommit {
{
Sha1 : "abcdef1" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user4@example.com" ,
AuthorName : "User Four" ,
Message : "close #1" ,
} ,
}
repo = AssertExistsAndLoadBean ( t , & Repository { ID : 3 } ) . ( * Repository )
commentBean = & Comment {
Type : CommentTypeCommitRef ,
CommitSHA : "abcdef1" ,
PosterID : user . ID ,
IssueID : 6 ,
}
issueBean = & Issue { RepoID : repo . ID , Index : 1 }
AssertNotExistsBean ( t , commentBean )
AssertNotExistsBean ( t , & Issue { RepoID : repo . ID , Index : 1 } , "is_closed=1" )
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , "non-existing-branch" ) )
AssertExistsAndLoadBean ( t , commentBean )
AssertNotExistsBean ( t , issueBean , "is_closed=1" )
CheckConsistencyFor ( t , & Action { } )
2017-01-09 06:08:36 +03:00
}
2019-06-15 07:00:32 +03:00
func TestUpdateIssuesCommit_Colon ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
pushCommits := [ ] * PushCommit {
{
Sha1 : "abcdef2" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User Two" ,
Message : "close: #2" ,
} ,
}
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 1 } ) . ( * Repository )
repo . Owner = user
issueBean := & Issue { RepoID : repo . ID , Index : 2 }
AssertNotExistsBean ( t , & Issue { RepoID : repo . ID , Index : 2 } , "is_closed=1" )
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , repo . DefaultBranch ) )
AssertExistsAndLoadBean ( t , issueBean , "is_closed=1" )
CheckConsistencyFor ( t , & Action { } )
}
2019-02-10 22:27:19 +03:00
func TestUpdateIssuesCommit_Issue5957 ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
// Test that push to a non-default branch closes an issue.
pushCommits := [ ] * PushCommit {
{
Sha1 : "abcdef1" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user4@example.com" ,
AuthorName : "User Four" ,
Message : "close #2" ,
} ,
}
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 2 } ) . ( * Repository )
commentBean := & Comment {
Type : CommentTypeCommitRef ,
CommitSHA : "abcdef1" ,
PosterID : user . ID ,
IssueID : 7 ,
}
issueBean := & Issue { RepoID : repo . ID , Index : 2 , ID : 7 }
AssertNotExistsBean ( t , commentBean )
AssertNotExistsBean ( t , issueBean , "is_closed=1" )
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , "non-existing-branch" ) )
AssertExistsAndLoadBean ( t , commentBean )
AssertExistsAndLoadBean ( t , issueBean , "is_closed=1" )
CheckConsistencyFor ( t , & Action { } )
}
2019-05-01 19:21:05 +03:00
func TestUpdateIssuesCommit_AnotherRepo ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
// Test that a push to default branch closes issue in another repo
// If the user also has push permissions to that repo
pushCommits := [ ] * PushCommit {
{
Sha1 : "abcdef1" ,
CommitterEmail : "user2@example.com" ,
CommitterName : "User Two" ,
AuthorEmail : "user2@example.com" ,
AuthorName : "User Two" ,
Message : "close user2/repo1#1" ,
} ,
}
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 2 } ) . ( * Repository )
commentBean := & Comment {
Type : CommentTypeCommitRef ,
CommitSHA : "abcdef1" ,
PosterID : user . ID ,
IssueID : 1 ,
}
issueBean := & Issue { RepoID : 1 , Index : 1 , ID : 1 }
AssertNotExistsBean ( t , commentBean )
AssertNotExistsBean ( t , issueBean , "is_closed=1" )
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , repo . DefaultBranch ) )
AssertExistsAndLoadBean ( t , commentBean )
AssertExistsAndLoadBean ( t , issueBean , "is_closed=1" )
CheckConsistencyFor ( t , & Action { } )
}
func TestUpdateIssuesCommit_AnotherRepoNoPermission ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
user := AssertExistsAndLoadBean ( t , & User { ID : 10 } ) . ( * User )
// Test that a push with close reference *can not* close issue
// If the commiter doesn't have push rights in that repo
pushCommits := [ ] * PushCommit {
{
Sha1 : "abcdef3" ,
CommitterEmail : "user10@example.com" ,
CommitterName : "User Ten" ,
AuthorEmail : "user10@example.com" ,
AuthorName : "User Ten" ,
Message : "close user3/repo3#1" ,
} ,
}
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 6 } ) . ( * Repository )
commentBean := & Comment {
Type : CommentTypeCommitRef ,
CommitSHA : "abcdef3" ,
PosterID : user . ID ,
IssueID : 6 ,
}
issueBean := & Issue { RepoID : 3 , Index : 1 , ID : 6 }
AssertNotExistsBean ( t , commentBean )
AssertNotExistsBean ( t , issueBean , "is_closed=1" )
assert . NoError ( t , UpdateIssuesCommit ( user , repo , pushCommits , repo . DefaultBranch ) )
2019-10-14 01:29:10 +03:00
AssertNotExistsBean ( t , commentBean )
2019-05-01 19:21:05 +03:00
AssertNotExistsBean ( t , issueBean , "is_closed=1" )
CheckConsistencyFor ( t , & Action { } )
}
2017-01-09 06:08:36 +03:00
func TestTransferRepoAction ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-01-25 05:49:51 +03:00
user2 := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
user4 := AssertExistsAndLoadBean ( t , & User { ID : 4 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 1 , OwnerID : user2 . ID } ) . ( * Repository )
2017-01-09 06:08:36 +03:00
repo . OwnerID = user4 . ID
repo . Owner = user4
actionBean := & Action {
2017-05-26 04:38:18 +03:00
OpType : ActionTransferRepo ,
ActUserID : user2 . ID ,
ActUser : user2 ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
2017-01-09 06:08:36 +03:00
}
AssertNotExistsBean ( t , actionBean )
assert . NoError ( t , TransferRepoAction ( user2 , user2 , repo ) )
AssertExistsAndLoadBean ( t , actionBean )
2017-02-28 04:42:10 +03:00
2017-10-05 07:43:04 +03:00
_ , err := x . ID ( repo . ID ) . Cols ( "owner_id" ) . Update ( repo )
2017-02-28 04:42:10 +03:00
assert . NoError ( t , err )
CheckConsistencyFor ( t , & Action { } )
2017-01-09 06:08:36 +03:00
}
func TestMergePullRequestAction ( t * testing . T ) {
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-01-25 05:49:51 +03:00
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
repo := AssertExistsAndLoadBean ( t , & Repository { ID : 1 , OwnerID : user . ID } ) . ( * Repository )
2017-01-09 06:08:36 +03:00
repo . Owner = user
2017-01-25 05:49:51 +03:00
issue := AssertExistsAndLoadBean ( t , & Issue { ID : 3 , RepoID : repo . ID } ) . ( * Issue )
2017-01-09 06:08:36 +03:00
actionBean := & Action {
2017-05-26 04:38:18 +03:00
OpType : ActionMergePullRequest ,
ActUserID : user . ID ,
ActUser : user ,
RepoID : repo . ID ,
Repo : repo ,
IsPrivate : repo . IsPrivate ,
2017-01-09 06:08:36 +03:00
}
AssertNotExistsBean ( t , actionBean )
assert . NoError ( t , MergePullRequestAction ( user , repo , issue ) )
AssertExistsAndLoadBean ( t , actionBean )
2017-02-28 04:42:10 +03:00
CheckConsistencyFor ( t , & Action { } )
2017-01-09 06:08:36 +03:00
}
func TestGetFeeds ( t * testing . T ) {
// test with an individual user
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-01-25 05:49:51 +03:00
user := AssertExistsAndLoadBean ( t , & User { ID : 2 } ) . ( * User )
2017-01-09 06:08:36 +03:00
2017-06-02 03:42:25 +03:00
actions , err := GetFeeds ( GetFeedsOptions {
RequestedUser : user ,
RequestingUserID : user . ID ,
IncludePrivate : true ,
OnlyPerformedBy : false ,
2017-06-25 21:20:29 +03:00
IncludeDeleted : true ,
2017-06-02 03:42:25 +03:00
} )
2017-01-09 06:08:36 +03:00
assert . NoError ( t , err )
2017-08-28 12:17:45 +03:00
if assert . Len ( t , actions , 1 ) {
assert . EqualValues ( t , 1 , actions [ 0 ] . ID )
assert . EqualValues ( t , user . ID , actions [ 0 ] . UserID )
}
2017-06-02 03:42:25 +03:00
actions , err = GetFeeds ( GetFeedsOptions {
RequestedUser : user ,
RequestingUserID : user . ID ,
IncludePrivate : false ,
OnlyPerformedBy : false ,
} )
2017-01-09 06:08:36 +03:00
assert . NoError ( t , err )
assert . Len ( t , actions , 0 )
}
func TestGetFeeds2 ( t * testing . T ) {
// test with an organization user
assert . NoError ( t , PrepareTestDatabase ( ) )
2017-06-02 03:42:25 +03:00
org := AssertExistsAndLoadBean ( t , & User { ID : 3 } ) . ( * User )
2018-01-08 10:48:37 +03:00
const userID = 2 // user2 is an owner of the organization
2017-06-02 03:42:25 +03:00
actions , err := GetFeeds ( GetFeedsOptions {
RequestedUser : org ,
RequestingUserID : userID ,
IncludePrivate : true ,
OnlyPerformedBy : false ,
2017-06-25 21:20:29 +03:00
IncludeDeleted : true ,
2017-06-02 03:42:25 +03:00
} )
2017-01-09 06:08:36 +03:00
assert . NoError ( t , err )
assert . Len ( t , actions , 1 )
2017-08-28 12:17:45 +03:00
if assert . Len ( t , actions , 1 ) {
assert . EqualValues ( t , 2 , actions [ 0 ] . ID )
assert . EqualValues ( t , org . ID , actions [ 0 ] . UserID )
}
2017-06-02 03:42:25 +03:00
actions , err = GetFeeds ( GetFeedsOptions {
RequestedUser : org ,
RequestingUserID : userID ,
IncludePrivate : false ,
OnlyPerformedBy : false ,
2017-06-25 21:20:29 +03:00
IncludeDeleted : true ,
2017-06-02 03:42:25 +03:00
} )
2017-01-09 06:08:36 +03:00
assert . NoError ( t , err )
2017-02-28 04:42:10 +03:00
assert . Len ( t , actions , 0 )
2017-01-09 06:08:36 +03:00
}