forked from lug/matterbridge
		
	
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
 | 
						|
// See LICENSE.txt for license information.
 | 
						|
 | 
						|
package model
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"image"
 | 
						|
	"image/gif"
 | 
						|
	"io"
 | 
						|
	"mime"
 | 
						|
	"net/http"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	FILEINFO_SORT_BY_CREATED = "CreateAt"
 | 
						|
	FILEINFO_SORT_BY_SIZE    = "Size"
 | 
						|
)
 | 
						|
 | 
						|
// GetFileInfosOptions contains options for getting FileInfos
 | 
						|
type GetFileInfosOptions struct {
 | 
						|
	// UserIds optionally limits the FileInfos to those created by the given users.
 | 
						|
	UserIds []string `json:"user_ids"`
 | 
						|
	// ChannelIds optionally limits the FileInfos to those created in the given channels.
 | 
						|
	ChannelIds []string `json:"channel_ids"`
 | 
						|
	// Since optionally limits FileInfos to those created at or after the given time, specified as Unix time in milliseconds.
 | 
						|
	Since int64 `json:"since"`
 | 
						|
	// IncludeDeleted if set includes deleted FileInfos.
 | 
						|
	IncludeDeleted bool `json:"include_deleted"`
 | 
						|
	// SortBy sorts the FileInfos by this field. The default is to sort by date created.
 | 
						|
	SortBy string `json:"sort_by"`
 | 
						|
	// SortDescending changes the sort direction to descending order when true.
 | 
						|
	SortDescending bool `json:"sort_descending"`
 | 
						|
}
 | 
						|
 | 
						|
type FileInfo struct {
 | 
						|
	Id              string  `json:"id"`
 | 
						|
	CreatorId       string  `json:"user_id"`
 | 
						|
	PostId          string  `json:"post_id,omitempty"`
 | 
						|
	CreateAt        int64   `json:"create_at"`
 | 
						|
	UpdateAt        int64   `json:"update_at"`
 | 
						|
	DeleteAt        int64   `json:"delete_at"`
 | 
						|
	Path            string  `json:"-"` // not sent back to the client
 | 
						|
	ThumbnailPath   string  `json:"-"` // not sent back to the client
 | 
						|
	PreviewPath     string  `json:"-"` // not sent back to the client
 | 
						|
	Name            string  `json:"name"`
 | 
						|
	Extension       string  `json:"extension"`
 | 
						|
	Size            int64   `json:"size"`
 | 
						|
	MimeType        string  `json:"mime_type"`
 | 
						|
	Width           int     `json:"width,omitempty"`
 | 
						|
	Height          int     `json:"height,omitempty"`
 | 
						|
	HasPreviewImage bool    `json:"has_preview_image,omitempty"`
 | 
						|
	MiniPreview     *[]byte `json:"mini_preview"` // declared as *[]byte to avoid postgres/mysql differences in deserialization
 | 
						|
}
 | 
						|
 | 
						|
func (fi *FileInfo) ToJson() string {
 | 
						|
	b, _ := json.Marshal(fi)
 | 
						|
	return string(b)
 | 
						|
}
 | 
						|
 | 
						|
func FileInfoFromJson(data io.Reader) *FileInfo {
 | 
						|
	decoder := json.NewDecoder(data)
 | 
						|
 | 
						|
	var fi FileInfo
 | 
						|
	if err := decoder.Decode(&fi); err != nil {
 | 
						|
		return nil
 | 
						|
	} else {
 | 
						|
		return &fi
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func FileInfosToJson(infos []*FileInfo) string {
 | 
						|
	b, _ := json.Marshal(infos)
 | 
						|
	return string(b)
 | 
						|
}
 | 
						|
 | 
						|
func FileInfosFromJson(data io.Reader) []*FileInfo {
 | 
						|
	decoder := json.NewDecoder(data)
 | 
						|
 | 
						|
	var infos []*FileInfo
 | 
						|
	if err := decoder.Decode(&infos); err != nil {
 | 
						|
		return nil
 | 
						|
	} else {
 | 
						|
		return infos
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (fi *FileInfo) PreSave() {
 | 
						|
	if fi.Id == "" {
 | 
						|
		fi.Id = NewId()
 | 
						|
	}
 | 
						|
 | 
						|
	if fi.CreateAt == 0 {
 | 
						|
		fi.CreateAt = GetMillis()
 | 
						|
	}
 | 
						|
 | 
						|
	if fi.UpdateAt < fi.CreateAt {
 | 
						|
		fi.UpdateAt = fi.CreateAt
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (fi *FileInfo) IsValid() *AppError {
 | 
						|
	if !IsValidId(fi.Id) {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "", http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	if !IsValidId(fi.CreatorId) && fi.CreatorId != "nouser" {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	if len(fi.PostId) != 0 && !IsValidId(fi.PostId) {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	if fi.CreateAt == 0 {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	if fi.UpdateAt == 0 {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	if fi.Path == "" {
 | 
						|
		return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+fi.Id, http.StatusBadRequest)
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (fi *FileInfo) IsImage() bool {
 | 
						|
	return strings.HasPrefix(fi.MimeType, "image")
 | 
						|
}
 | 
						|
 | 
						|
func NewInfo(name string) *FileInfo {
 | 
						|
	info := &FileInfo{
 | 
						|
		Name: name,
 | 
						|
	}
 | 
						|
 | 
						|
	extension := strings.ToLower(filepath.Ext(name))
 | 
						|
	info.MimeType = mime.TypeByExtension(extension)
 | 
						|
 | 
						|
	if extension != "" && extension[0] == '.' {
 | 
						|
		// The client expects a file extension without the leading period
 | 
						|
		info.Extension = extension[1:]
 | 
						|
	} else {
 | 
						|
		info.Extension = extension
 | 
						|
	}
 | 
						|
 | 
						|
	return info
 | 
						|
}
 | 
						|
 | 
						|
func GetInfoForBytes(name string, data io.ReadSeeker, size int) (*FileInfo, *AppError) {
 | 
						|
	info := &FileInfo{
 | 
						|
		Name: name,
 | 
						|
		Size: int64(size),
 | 
						|
	}
 | 
						|
	var err *AppError
 | 
						|
 | 
						|
	extension := strings.ToLower(filepath.Ext(name))
 | 
						|
	info.MimeType = mime.TypeByExtension(extension)
 | 
						|
 | 
						|
	if extension != "" && extension[0] == '.' {
 | 
						|
		// The client expects a file extension without the leading period
 | 
						|
		info.Extension = extension[1:]
 | 
						|
	} else {
 | 
						|
		info.Extension = extension
 | 
						|
	}
 | 
						|
 | 
						|
	if info.IsImage() {
 | 
						|
		// Only set the width and height if it's actually an image that we can understand
 | 
						|
		if config, _, err := image.DecodeConfig(data); err == nil {
 | 
						|
			info.Width = config.Width
 | 
						|
			info.Height = config.Height
 | 
						|
 | 
						|
			if info.MimeType == "image/gif" {
 | 
						|
				// Just show the gif itself instead of a preview image for animated gifs
 | 
						|
				data.Seek(0, io.SeekStart)
 | 
						|
				if gifConfig, err := gif.DecodeAll(data); err != nil {
 | 
						|
					// Still return the rest of the info even though it doesn't appear to be an actual gif
 | 
						|
					info.HasPreviewImage = true
 | 
						|
					return info, NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, err.Error(), http.StatusBadRequest)
 | 
						|
				} else {
 | 
						|
					info.HasPreviewImage = len(gifConfig.Image) == 1
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				info.HasPreviewImage = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return info, err
 | 
						|
}
 | 
						|
 | 
						|
func GetEtagForFileInfos(infos []*FileInfo) string {
 | 
						|
	if len(infos) == 0 {
 | 
						|
		return Etag()
 | 
						|
	}
 | 
						|
 | 
						|
	var maxUpdateAt int64
 | 
						|
 | 
						|
	for _, info := range infos {
 | 
						|
		if info.UpdateAt > maxUpdateAt {
 | 
						|
			maxUpdateAt = info.UpdateAt
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return Etag(infos[0].PostId, maxUpdateAt)
 | 
						|
}
 |