@ -7,6 +7,9 @@ package models
import (
import (
"bytes"
"bytes"
"fmt"
"fmt"
"image"
_ "image/jpeg"
"image/png"
"io/ioutil"
"io/ioutil"
"os"
"os"
"os/exec"
"os/exec"
@ -15,15 +18,12 @@ import (
"sort"
"sort"
"strings"
"strings"
"time"
"time"
"image"
_ "image/jpeg"
"image/png"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/cae/zip"
"github.com/Unknwon/com"
"github.com/Unknwon/com"
"github.com/go-xorm/xorm"
"github.com/go-xorm/xorm"
"github.com/nfnt/resize"
"github.com/mcuadros/go-version"
"github.com/mcuadros/go-version"
"github.com/nfnt/resize"
log "gopkg.in/clog.v1"
log "gopkg.in/clog.v1"
"gopkg.in/ini.v1"
"gopkg.in/ini.v1"
@ -39,6 +39,9 @@ import (
"github.com/gogs/gogs/pkg/sync"
"github.com/gogs/gogs/pkg/sync"
)
)
// REPO_AVATAR_URL_PREFIX is used to identify a URL is to access repository avatar.
const REPO_AVATAR_URL_PREFIX = "repo-avatars"
var repoWorkingPool = sync . NewExclusivePool ( )
var repoWorkingPool = sync . NewExclusivePool ( )
var (
var (
@ -146,16 +149,18 @@ func NewRepoContext() {
// Repository contains information of a repository.
// Repository contains information of a repository.
type Repository struct {
type Repository struct {
ID int64
ID int64
OwnerID int64 ` xorm:"UNIQUE(s)" `
OwnerID int64 ` xorm:"UNIQUE(s)" `
Owner * User ` xorm:"-" json:"-" `
Owner * User ` xorm:"-" json:"-" `
LowerName string ` xorm:"UNIQUE(s) INDEX NOT NULL" `
LowerName string ` xorm:"UNIQUE(s) INDEX NOT NULL" `
Name string ` xorm:"INDEX NOT NULL" `
Name string ` xorm:"INDEX NOT NULL" `
Description string ` xorm:"VARCHAR(512)" `
Description string ` xorm:"VARCHAR(512)" `
Website string
Website string
DefaultBranch string
DefaultBranch string
Size int64 ` xorm:"NOT NULL DEFAULT 0" `
Size int64 ` xorm:"NOT NULL DEFAULT 0" `
UseCustomAvatar bool
// Counters
NumWatches int
NumWatches int
NumStars int
NumStars int
NumForks int
NumForks int
@ -302,10 +307,10 @@ func (repo *Repository) RelAvatarLink() string {
if ! com . IsExist ( repo . CustomAvatarPath ( ) ) {
if ! com . IsExist ( repo . CustomAvatarPath ( ) ) {
return defaultImgUrl
return defaultImgUrl
}
}
return setting . AppSubURL + "/repo-avatars/" + com . ToStr ( repo . ID )
return fmt . Sprintf ( "%s/%s/%d" , setting . AppSubURL , REPO_AVATAR_URL_PREFIX , repo . ID )
}
}
// AvatarLink returns user avatar absolute link.
// AvatarLink returns repository avatar absolute link.
func ( repo * Repository ) AvatarLink ( ) string {
func ( repo * Repository ) AvatarLink ( ) string {
link := repo . RelAvatarLink ( )
link := repo . RelAvatarLink ( )
if link [ 0 ] == '/' && link [ 1 ] != '/' {
if link [ 0 ] == '/' && link [ 1 ] != '/' {
@ -315,24 +320,23 @@ func (repo *Repository) AvatarLink() string {
}
}
// UploadAvatar saves custom avatar for repository.
// UploadAvatar saves custom avatar for repository.
// FIXME: split uploads to different subdirs
// FIXME: split uploads to different subdirs in case we have massive number of repositories.
// in case we have massive number of repositories.
func ( repo * Repository ) UploadAvatar ( data [ ] byte ) error {
func ( repo * Repository ) UploadAvatar ( data [ ] byte ) error {
img , _ , err := image . Decode ( bytes . NewReader ( data ) )
img , _ , err := image . Decode ( bytes . NewReader ( data ) )
if err != nil {
if err != nil {
return fmt . Errorf ( "Decod e: %v" , err )
return fmt . Errorf ( "decode imag e: %v" , err )
}
}
m := resize . Resize ( avatar . AVATAR_SIZE , avatar . AVATAR_SIZE , img , resize . NearestNeighbor )
os . MkdirAll ( setting . RepositoryAvatarUploadPath , os . ModePerm )
os . MkdirAll ( setting . RepositoryAvatarUploadPath , os . ModePerm )
fw , err := os . Create ( repo . CustomAvatarPath ( ) )
fw , err := os . Create ( repo . CustomAvatarPath ( ) )
if err != nil {
if err != nil {
return fmt . Errorf ( "Create : %v" , err )
return fmt . Errorf ( "create custom avatar directory : %v" , err )
}
}
defer fw . Close ( )
defer fw . Close ( )
m := resize . Resize ( avatar . AVATAR_SIZE , avatar . AVATAR_SIZE , img , resize . NearestNeighbor )
if err = png . Encode ( fw , m ) ; err != nil {
if err = png . Encode ( fw , m ) ; err != nil {
return fmt . Errorf ( "Encod e: %v" , err )
return fmt . Errorf ( "encode imag e: %v" , err )
}
}
return nil
return nil
@ -341,7 +345,12 @@ func (repo *Repository) UploadAvatar(data []byte) error {
// DeleteAvatar deletes the repository custom avatar.
// DeleteAvatar deletes the repository custom avatar.
func ( repo * Repository ) DeleteAvatar ( ) error {
func ( repo * Repository ) DeleteAvatar ( ) error {
log . Trace ( "DeleteAvatar [%d]: %s" , repo . ID , repo . CustomAvatarPath ( ) )
log . Trace ( "DeleteAvatar [%d]: %s" , repo . ID , repo . CustomAvatarPath ( ) )
return os . Remove ( repo . CustomAvatarPath ( ) )
if err := os . Remove ( repo . CustomAvatarPath ( ) ) ; err != nil {
return err
}
repo . UseCustomAvatar = false
return UpdateRepository ( repo , false )
}
}
// This method assumes following fields have been assigned with valid values:
// This method assumes following fields have been assigned with valid values:
@ -372,8 +381,8 @@ func (repo *Repository) APIFormat(permission *api.Permission, user ...*User) *ap
Created : repo . Created ,
Created : repo . Created ,
Updated : repo . Updated ,
Updated : repo . Updated ,
Permissions : permission ,
Permissions : permission ,
// Reserved for go-gogs-client change
// Reserved for go-gogs-client change
// AvatarUrl: repo.AvatarLink(),
// AvatarUrl: repo.AvatarLink(),
}
}
if repo . IsFork {
if repo . IsFork {
p := & api . Permission { Pull : true }
p := & api . Permission { Pull : true }