use shared cache
This commit is contained in:
parent
770d8925bf
commit
26172fbd89
@ -1,19 +1,19 @@
|
||||
# Golang CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
|
||||
working_directory: /go/src/github.com/{{ORG_NAME}}/{{REPO_NAME}}
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# specify any bash command here prefixed with `run: `
|
||||
- run: go get -v ./cmd/panel/
|
||||
- run: go build ./cmd/panel/main.go
|
||||
|
||||
- store_artifacts:
|
||||
# Golang CircleCI 2.0 configuration file
|
||||
#
|
||||
# Check https://circleci.com/docs/2.0/language-go/ for more details
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.12
|
||||
|
||||
working_directory: /go/src/github.com/{{ORG_NAME}}/{{REPO_NAME}}
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# specify any bash command here prefixed with `run: `
|
||||
- run: go get -v ./cmd/panel/
|
||||
- run: go build ./cmd/panel/main.go
|
||||
|
||||
- store_artifacts:
|
||||
path: /go/src/github.com/{{ORG_NAME}}/{{REPO_NAME}}/main
|
18
.gitattributes
vendored
18
.gitattributes
vendored
@ -1,9 +1,9 @@
|
||||
public/static/css/animate.min.css linguist-vendored
|
||||
public/static/css/bootstrap.min.css linguist-vendored
|
||||
public/static/css/light-bootstrap-dashboard.css linguist-vendored
|
||||
public/static/js/bootstrap-notify.js linguist-vendored
|
||||
public/static/js/bootstrap-select.js linguist-vendored
|
||||
public/static/js/bootstrap.min.js linguist-vendored
|
||||
public/static/js/chartist.min.js linguist-vendored
|
||||
public/static/js/jquery.3.2.1.min.js linguist-vendored
|
||||
public/static/js/light-bootstrap-dashboard.js linguist-vendored
|
||||
public/static/css/animate.min.css linguist-vendored
|
||||
public/static/css/bootstrap.min.css linguist-vendored
|
||||
public/static/css/light-bootstrap-dashboard.css linguist-vendored
|
||||
public/static/js/bootstrap-notify.js linguist-vendored
|
||||
public/static/js/bootstrap-select.js linguist-vendored
|
||||
public/static/js/bootstrap.min.js linguist-vendored
|
||||
public/static/js/chartist.min.js linguist-vendored
|
||||
public/static/js/jquery.3.2.1.min.js linguist-vendored
|
||||
public/static/js/light-bootstrap-dashboard.js linguist-vendored
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
config.toml
|
||||
*.iml
|
||||
.idea
|
||||
config.toml
|
||||
*.iml
|
||||
.idea
|
||||
|
@ -114,17 +114,20 @@ func UpdateSettingsHandler(ctx *gin.Context) {
|
||||
|
||||
// Archive channel
|
||||
// Create a list of IDs
|
||||
var channelIds []string
|
||||
for _, c := range guild.Channels {
|
||||
channelIds = append(channelIds, c.Id)
|
||||
channelsChan := make(chan []table.Channel)
|
||||
go table.GetCachedChannelsByGuild(guildId, channelsChan)
|
||||
channels := <-channelsChan
|
||||
|
||||
var channelIds []int64
|
||||
for _, channel := range channels {
|
||||
channelIds = append(channelIds, channel.ChannelId)
|
||||
}
|
||||
|
||||
// Update or archive channel
|
||||
archiveChannelStr := ctx.PostForm("archivechannel")
|
||||
if utils.Contains(channelIds, archiveChannelStr) {
|
||||
// Error is impossible, as we check it's a valid channel already
|
||||
parsed, _ := strconv.ParseInt(archiveChannelStr, 10, 64)
|
||||
table.UpdateArchiveChannel(guildId, parsed)
|
||||
archiveChannelId, err := strconv.ParseInt(archiveChannelStr, 10, 64)
|
||||
if err == nil && utils.Contains(channelIds, archiveChannelId) {
|
||||
table.UpdateArchiveChannel(guildId, archiveChannelId)
|
||||
}
|
||||
|
||||
// Users can close
|
||||
|
@ -1,25 +1,25 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func LoginHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl)
|
||||
} else {
|
||||
redirect := url.QueryEscape(config.Conf.Oauth.RedirectUri)
|
||||
ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify+guilds&client_id=%d", redirect, config.Conf.Oauth.Id))
|
||||
}
|
||||
}
|
||||
package root
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/TicketsBot/GoPanel/utils"
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func LoginHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
if utils.IsLoggedIn(store) {
|
||||
ctx.Redirect(302, config.Conf.Server.BaseUrl)
|
||||
} else {
|
||||
redirect := url.QueryEscape(config.Conf.Oauth.RedirectUri)
|
||||
ctx.Redirect(302, fmt.Sprintf("https://discordapp.com/oauth2/authorize?response_type=code&redirect_uri=%s&scope=identify+guilds&client_id=%d", redirect, config.Conf.Oauth.Id))
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func LogoutHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
store.Clear()
|
||||
ctx.Redirect(302, "https://ticketsbot.net")
|
||||
}
|
||||
package root
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func LogoutHandler(ctx *gin.Context) {
|
||||
store := sessions.Default(ctx)
|
||||
if store == nil {
|
||||
return
|
||||
}
|
||||
defer store.Save()
|
||||
|
||||
store.Clear()
|
||||
ctx.Redirect(302, "https://ticketsbot.net")
|
||||
}
|
||||
|
50
cache/redis.go
vendored
50
cache/redis.go
vendored
@ -1,25 +1,25 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/go-redis/redis"
|
||||
)
|
||||
|
||||
type RedisClient struct {
|
||||
*redis.Client
|
||||
}
|
||||
|
||||
var Client RedisClient
|
||||
|
||||
func NewRedisClient() RedisClient {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", config.Conf.Redis.Host, config.Conf.Redis.Port),
|
||||
Password: config.Conf.Redis.Password,
|
||||
PoolSize: config.Conf.Redis.Threads,
|
||||
})
|
||||
|
||||
return RedisClient{
|
||||
client,
|
||||
}
|
||||
}
|
||||
package cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/go-redis/redis"
|
||||
)
|
||||
|
||||
type RedisClient struct {
|
||||
*redis.Client
|
||||
}
|
||||
|
||||
var Client RedisClient
|
||||
|
||||
func NewRedisClient() RedisClient {
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: fmt.Sprintf("%s:%d", config.Conf.Redis.Host, config.Conf.Redis.Port),
|
||||
Password: config.Conf.Redis.Password,
|
||||
PoolSize: config.Conf.Redis.Threads,
|
||||
})
|
||||
|
||||
return RedisClient{
|
||||
client,
|
||||
}
|
||||
}
|
||||
|
42
cache/uriparser.go
vendored
42
cache/uriparser.go
vendored
@ -1,21 +1,21 @@
|
||||
package cache
|
||||
|
||||
import "net/url"
|
||||
|
||||
type RedisURI struct {
|
||||
Addr string
|
||||
Password string
|
||||
}
|
||||
|
||||
func ParseURI(raw string) RedisURI {
|
||||
parsed, err := url.Parse(raw); if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
passwd, _ := parsed.User.Password()
|
||||
|
||||
return RedisURI{
|
||||
Addr: parsed.Host,
|
||||
Password: passwd,
|
||||
}
|
||||
}
|
||||
package cache
|
||||
|
||||
import "net/url"
|
||||
|
||||
type RedisURI struct {
|
||||
Addr string
|
||||
Password string
|
||||
}
|
||||
|
||||
func ParseURI(raw string) RedisURI {
|
||||
parsed, err := url.Parse(raw); if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
passwd, _ := parsed.User.Password()
|
||||
|
||||
return RedisURI{
|
||||
Addr: parsed.Host,
|
||||
Password: passwd,
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
admins=["217617036749176833"]
|
||||
|
||||
[server]
|
||||
host="0.0.0.0:3000"
|
||||
baseUrl="http://localhost:3000"
|
||||
mainSite="https://ticketsbot.net"
|
||||
[server.ratelimit]
|
||||
window=10
|
||||
max=600
|
||||
[server.session]
|
||||
threads=10
|
||||
secret="secret"
|
||||
|
||||
[oauth]
|
||||
id=
|
||||
secret=""
|
||||
redirectUri=""
|
||||
|
||||
[mariadb]
|
||||
host="127.0.0.1"
|
||||
username="ryan"
|
||||
password="ryan"
|
||||
database="tickets"
|
||||
threads=5
|
||||
|
||||
[bot]
|
||||
token=""
|
||||
premium-lookup-proxy-url="http://localhost:3000"
|
||||
premium-lookup-proxy-key=""
|
||||
|
||||
[redis]
|
||||
host="127.0.0.1"
|
||||
port=6379
|
||||
password=""
|
||||
threads=5
|
||||
admins=["217617036749176833"]
|
||||
|
||||
[server]
|
||||
host="0.0.0.0:3000"
|
||||
baseUrl="http://localhost:3000"
|
||||
mainSite="https://ticketsbot.net"
|
||||
[server.ratelimit]
|
||||
window=10
|
||||
max=600
|
||||
[server.session]
|
||||
threads=10
|
||||
secret="secret"
|
||||
|
||||
[oauth]
|
||||
id=
|
||||
secret=""
|
||||
redirectUri=""
|
||||
|
||||
[mariadb]
|
||||
host="127.0.0.1"
|
||||
username="ryan"
|
||||
password="ryan"
|
||||
database="tickets"
|
||||
threads=5
|
||||
|
||||
[bot]
|
||||
token=""
|
||||
premium-lookup-proxy-url="http://localhost:3000"
|
||||
premium-lookup-proxy-key=""
|
||||
|
||||
[redis]
|
||||
host="127.0.0.1"
|
||||
port=6379
|
||||
password=""
|
||||
threads=5
|
||||
|
156
config/config.go
156
config/config.go
@ -1,78 +1,78 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
Admins []string
|
||||
Server Server
|
||||
Oauth Oauth
|
||||
MariaDB MariaDB
|
||||
Bot Bot
|
||||
Redis Redis
|
||||
}
|
||||
|
||||
Server struct {
|
||||
Host string
|
||||
BaseUrl string
|
||||
MainSite string
|
||||
Ratelimit Ratelimit
|
||||
Session Session
|
||||
}
|
||||
|
||||
Ratelimit struct {
|
||||
Window int
|
||||
Max int
|
||||
}
|
||||
|
||||
Session struct {
|
||||
Threads int
|
||||
Secret string
|
||||
}
|
||||
|
||||
Oauth struct {
|
||||
Id int64
|
||||
Secret string
|
||||
RedirectUri string
|
||||
}
|
||||
|
||||
MariaDB struct {
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
Database string
|
||||
Threads int
|
||||
}
|
||||
|
||||
Bot struct {
|
||||
Token string
|
||||
PremiumLookupProxyUrl string `toml:"premium-lookup-proxy-url"`
|
||||
PremiumLookupProxyKey string `toml:"premium-lookup-proxy-key"`
|
||||
}
|
||||
|
||||
Redis struct {
|
||||
Host string
|
||||
Port int
|
||||
Password string
|
||||
Threads int
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
Conf Config
|
||||
)
|
||||
|
||||
func LoadConfig() {
|
||||
raw, err := ioutil.ReadFile("config.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = toml.Decode(string(raw), &Conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
type (
|
||||
Config struct {
|
||||
Admins []string
|
||||
Server Server
|
||||
Oauth Oauth
|
||||
MariaDB MariaDB
|
||||
Bot Bot
|
||||
Redis Redis
|
||||
}
|
||||
|
||||
Server struct {
|
||||
Host string
|
||||
BaseUrl string
|
||||
MainSite string
|
||||
Ratelimit Ratelimit
|
||||
Session Session
|
||||
}
|
||||
|
||||
Ratelimit struct {
|
||||
Window int
|
||||
Max int
|
||||
}
|
||||
|
||||
Session struct {
|
||||
Threads int
|
||||
Secret string
|
||||
}
|
||||
|
||||
Oauth struct {
|
||||
Id int64
|
||||
Secret string
|
||||
RedirectUri string
|
||||
}
|
||||
|
||||
MariaDB struct {
|
||||
Host string
|
||||
Username string
|
||||
Password string
|
||||
Database string
|
||||
Threads int
|
||||
}
|
||||
|
||||
Bot struct {
|
||||
Token string
|
||||
PremiumLookupProxyUrl string `toml:"premium-lookup-proxy-url"`
|
||||
PremiumLookupProxyKey string `toml:"premium-lookup-proxy-key"`
|
||||
}
|
||||
|
||||
Redis struct {
|
||||
Host string
|
||||
Port int
|
||||
Password string
|
||||
Threads int
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
Conf Config
|
||||
)
|
||||
|
||||
func LoadConfig() {
|
||||
raw, err := ioutil.ReadFile("config.toml")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = toml.Decode(string(raw), &Conf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
Database gorm.DB
|
||||
)
|
||||
|
||||
func ConnectToDatabase() {
|
||||
uri := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:3306)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
config.Conf.MariaDB.Username,
|
||||
config.Conf.MariaDB.Password,
|
||||
config.Conf.MariaDB.Host,
|
||||
config.Conf.MariaDB.Database,
|
||||
)
|
||||
|
||||
db, err := gorm.Open("mysql", uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
db.DB().SetMaxOpenConns(config.Conf.MariaDB.Threads)
|
||||
db.DB().SetMaxIdleConns(0)
|
||||
|
||||
db.Set("gorm:table_options", "charset=utf8mb4")
|
||||
db.BlockGlobalUpdate(true)
|
||||
|
||||
Database = *db
|
||||
}
|
||||
package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jinzhu/gorm"
|
||||
)
|
||||
|
||||
var (
|
||||
Database gorm.DB
|
||||
)
|
||||
|
||||
func ConnectToDatabase() {
|
||||
uri := fmt.Sprintf(
|
||||
"%s:%s@tcp(%s:3306)/%s?charset=utf8mb4&parseTime=True&loc=Local",
|
||||
config.Conf.MariaDB.Username,
|
||||
config.Conf.MariaDB.Password,
|
||||
config.Conf.MariaDB.Host,
|
||||
config.Conf.MariaDB.Database,
|
||||
)
|
||||
|
||||
db, err := gorm.Open("mysql", uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
db.DB().SetMaxOpenConns(config.Conf.MariaDB.Threads)
|
||||
db.DB().SetMaxIdleConns(0)
|
||||
|
||||
db.Set("gorm:table_options", "charset=utf8mb4")
|
||||
db.BlockGlobalUpdate(true)
|
||||
|
||||
Database = *db
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
type ArchiveChannel struct {
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
Channel int64 `gorm:"column:CHANNELID"`
|
||||
}
|
||||
|
||||
@ -24,4 +24,3 @@ func GetArchiveChannel(guildId int64) int64 {
|
||||
|
||||
return channel.Channel
|
||||
}
|
||||
|
||||
|
@ -1,37 +1,37 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type BlacklistNode struct {
|
||||
Assoc int `gorm:"column:ASSOCID;type:int;primary_key;auto_increment"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
User int64 `gorm:"column:USERID"`
|
||||
}
|
||||
|
||||
func (BlacklistNode) TableName() string {
|
||||
return "blacklist"
|
||||
}
|
||||
|
||||
func IsBlacklisted(guildId, userId int64) bool {
|
||||
var count int
|
||||
database.Database.Table("blacklist").Where(&BlacklistNode{Guild: guildId, User: userId}).Count(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func AddBlacklist(guildId, userId int64) {
|
||||
database.Database.Create(&BlacklistNode{Guild: guildId, User: userId})
|
||||
}
|
||||
|
||||
func RemoveBlacklist(guildId, userId int64) {
|
||||
var node BlacklistNode
|
||||
database.Database.Where(BlacklistNode{Guild: guildId, User: userId}).Take(&node)
|
||||
database.Database.Delete(&node)
|
||||
}
|
||||
|
||||
func GetBlacklistNodes(guildId int64) []BlacklistNode {
|
||||
var nodes []BlacklistNode
|
||||
database.Database.Where(&BlacklistNode{Guild: guildId}).Find(&nodes)
|
||||
return nodes
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type BlacklistNode struct {
|
||||
Assoc int `gorm:"column:ASSOCID;type:int;primary_key;auto_increment"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
User int64 `gorm:"column:USERID"`
|
||||
}
|
||||
|
||||
func (BlacklistNode) TableName() string {
|
||||
return "blacklist"
|
||||
}
|
||||
|
||||
func IsBlacklisted(guildId, userId int64) bool {
|
||||
var count int
|
||||
database.Database.Table("blacklist").Where(&BlacklistNode{Guild: guildId, User: userId}).Count(&count)
|
||||
return count > 0
|
||||
}
|
||||
|
||||
func AddBlacklist(guildId, userId int64) {
|
||||
database.Database.Create(&BlacklistNode{Guild: guildId, User: userId})
|
||||
}
|
||||
|
||||
func RemoveBlacklist(guildId, userId int64) {
|
||||
var node BlacklistNode
|
||||
database.Database.Where(BlacklistNode{Guild: guildId, User: userId}).Take(&node)
|
||||
database.Database.Delete(&node)
|
||||
}
|
||||
|
||||
func GetBlacklistNodes(guildId int64) []BlacklistNode {
|
||||
var nodes []BlacklistNode
|
||||
database.Database.Where(&BlacklistNode{Guild: guildId}).Find(&nodes)
|
||||
return nodes
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type ChannelCategory struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Category int64 `gorm:"column:CATEGORYID"`
|
||||
}
|
||||
|
||||
func (ChannelCategory) TableName() string {
|
||||
return "channelcategory"
|
||||
}
|
||||
|
||||
func UpdateChannelCategory(guildId int64, categoryId int64) {
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).Assign(&ChannelCategory{Category: categoryId}).FirstOrCreate(&ChannelCategory{})
|
||||
}
|
||||
|
||||
func GetChannelCategory(guildId int64) int64 {
|
||||
var category ChannelCategory
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).First(&category)
|
||||
|
||||
return category.Category
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type ChannelCategory struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Category int64 `gorm:"column:CATEGORYID"`
|
||||
}
|
||||
|
||||
func (ChannelCategory) TableName() string {
|
||||
return "channelcategory"
|
||||
}
|
||||
|
||||
func UpdateChannelCategory(guildId int64, categoryId int64) {
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).Assign(&ChannelCategory{Category: categoryId}).FirstOrCreate(&ChannelCategory{})
|
||||
}
|
||||
|
||||
func GetChannelCategory(guildId int64) int64 {
|
||||
var category ChannelCategory
|
||||
database.Database.Where(&ChannelCategory{GuildId: guildId}).First(&category)
|
||||
|
||||
return category.Category
|
||||
}
|
||||
|
@ -1,38 +1,38 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
)
|
||||
|
||||
type GuildCache struct {
|
||||
UserId string `gorm:"column:USERID;type:varchar(20)"` // Apparently I made this a VARCHAR in the JS version
|
||||
Guilds string `gorm:"column:guilds;type:mediumtext"`
|
||||
}
|
||||
|
||||
func (GuildCache) TableName() string {
|
||||
return "guildscache"
|
||||
}
|
||||
|
||||
func UpdateGuilds(userId string, guilds string) {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).Assign(&GuildCache{Guilds: guilds}).FirstOrCreate(&cache)
|
||||
}
|
||||
|
||||
func GetGuilds(userId string) []objects.Guild {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).First(&cache)
|
||||
decoded, err := base64.StdEncoding.DecodeString(cache.Guilds)
|
||||
if err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
var guilds []objects.Guild
|
||||
if err := json.Unmarshal(decoded, &guilds); err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
return guilds
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
)
|
||||
|
||||
type GuildCache struct {
|
||||
UserId string `gorm:"column:USERID;type:varchar(20)"` // Apparently I made this a VARCHAR in the JS version
|
||||
Guilds string `gorm:"column:guilds;type:mediumtext"`
|
||||
}
|
||||
|
||||
func (GuildCache) TableName() string {
|
||||
return "guildscache"
|
||||
}
|
||||
|
||||
func UpdateGuilds(userId string, guilds string) {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).Assign(&GuildCache{Guilds: guilds}).FirstOrCreate(&cache)
|
||||
}
|
||||
|
||||
func GetGuilds(userId string) []objects.Guild {
|
||||
var cache GuildCache
|
||||
database.Database.Where(&GuildCache{UserId: userId}).First(&cache)
|
||||
decoded, err := base64.StdEncoding.DecodeString(cache.Guilds)
|
||||
if err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
var guilds []objects.Guild
|
||||
if err := json.Unmarshal(decoded, &guilds); err != nil {
|
||||
return make([]objects.Guild, 0)
|
||||
}
|
||||
|
||||
return guilds
|
||||
}
|
||||
|
@ -1,44 +1,44 @@
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type PermissionNode struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
UserId int64 `gorm:"column:USERID"`
|
||||
IsSupport bool `gorm:"column:ISSUPPORT"`
|
||||
IsAdmin bool `gorm:"column:ISADMIN"`
|
||||
}
|
||||
|
||||
func (PermissionNode) TableName() string {
|
||||
return "permissions"
|
||||
}
|
||||
|
||||
func GetAdminGuilds(userId int64) []int64 {
|
||||
var nodes []PermissionNode
|
||||
database.Database.Where(&PermissionNode{UserId: userId}).Find(&nodes)
|
||||
|
||||
ids := make([]int64, 0)
|
||||
for _, node := range nodes {
|
||||
ids = append(ids, node.GuildId)
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
func IsSupport(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsSupport
|
||||
}
|
||||
|
||||
func IsAdmin(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin
|
||||
}
|
||||
|
||||
func IsStaff(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin || node.IsSupport
|
||||
}
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type PermissionNode struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
UserId int64 `gorm:"column:USERID"`
|
||||
IsSupport bool `gorm:"column:ISSUPPORT"`
|
||||
IsAdmin bool `gorm:"column:ISADMIN"`
|
||||
}
|
||||
|
||||
func (PermissionNode) TableName() string {
|
||||
return "permissions"
|
||||
}
|
||||
|
||||
func GetAdminGuilds(userId int64) []int64 {
|
||||
var nodes []PermissionNode
|
||||
database.Database.Where(&PermissionNode{UserId: userId}).Find(&nodes)
|
||||
|
||||
ids := make([]int64, 0)
|
||||
for _, node := range nodes {
|
||||
ids = append(ids, node.GuildId)
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
func IsSupport(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsSupport
|
||||
}
|
||||
|
||||
func IsAdmin(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin
|
||||
}
|
||||
|
||||
func IsStaff(guildId int64, userId int64) bool {
|
||||
var node PermissionNode
|
||||
database.Database.Where(&PermissionNode{GuildId: guildId, UserId: userId}).Take(&node)
|
||||
return node.IsAdmin || node.IsSupport
|
||||
}
|
||||
|
@ -1,37 +1,37 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type PingEveryone struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
PingEveryone bool `gorm:"column:PINGEVERYONE;type:TINYINT"`
|
||||
}
|
||||
|
||||
func (PingEveryone) TableName() string {
|
||||
return "pingeveryone"
|
||||
}
|
||||
|
||||
// tldr I hate gorm
|
||||
func UpdatePingEveryone(guildId int64, pingEveryone bool) {
|
||||
var settings []PingEveryone
|
||||
database.Database.Where(&PingEveryone{GuildId: guildId}).Find(&settings)
|
||||
|
||||
updated := PingEveryone{guildId, pingEveryone}
|
||||
|
||||
if len(settings) == 0 {
|
||||
database.Database.Create(&updated)
|
||||
} else {
|
||||
database.Database.Table("pingeveryone").Where("GUILDID = ?", guildId).Update("PINGEVERYONE", pingEveryone)
|
||||
}
|
||||
|
||||
//database.Database.Where(&PingEveryone{GuildId: guildId}).Assign(&updated).FirstOrCreate(&PingEveryone{})
|
||||
}
|
||||
|
||||
func GetPingEveryone(guildId int64) bool {
|
||||
pingEveryone := PingEveryone{PingEveryone: true}
|
||||
database.Database.Where(&PingEveryone{GuildId: guildId}).First(&pingEveryone)
|
||||
|
||||
return pingEveryone.PingEveryone
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type PingEveryone struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
PingEveryone bool `gorm:"column:PINGEVERYONE;type:TINYINT"`
|
||||
}
|
||||
|
||||
func (PingEveryone) TableName() string {
|
||||
return "pingeveryone"
|
||||
}
|
||||
|
||||
// tldr I hate gorm
|
||||
func UpdatePingEveryone(guildId int64, pingEveryone bool) {
|
||||
var settings []PingEveryone
|
||||
database.Database.Where(&PingEveryone{GuildId: guildId}).Find(&settings)
|
||||
|
||||
updated := PingEveryone{guildId, pingEveryone}
|
||||
|
||||
if len(settings) == 0 {
|
||||
database.Database.Create(&updated)
|
||||
} else {
|
||||
database.Database.Table("pingeveryone").Where("GUILDID = ?", guildId).Update("PINGEVERYONE", pingEveryone)
|
||||
}
|
||||
|
||||
//database.Database.Where(&PingEveryone{GuildId: guildId}).Assign(&updated).FirstOrCreate(&PingEveryone{})
|
||||
}
|
||||
|
||||
func GetPingEveryone(guildId int64) bool {
|
||||
pingEveryone := PingEveryone{PingEveryone: true}
|
||||
database.Database.Where(&PingEveryone{GuildId: guildId}).First(&pingEveryone)
|
||||
|
||||
return pingEveryone.PingEveryone
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type Prefix struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Prefix string `gorm:"column:PREFIX;type:varchar(8)"`
|
||||
}
|
||||
|
||||
func (Prefix) TableName() string {
|
||||
return "prefix"
|
||||
}
|
||||
|
||||
func UpdatePrefix(guildId int64, prefix string) {
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).Assign(&Prefix{Prefix: prefix}).FirstOrCreate(&Prefix{})
|
||||
}
|
||||
|
||||
func GetPrefix(guildId int64) string {
|
||||
prefix := Prefix{Prefix: "t!"}
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).First(&prefix)
|
||||
|
||||
return prefix.Prefix
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type Prefix struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Prefix string `gorm:"column:PREFIX;type:varchar(8)"`
|
||||
}
|
||||
|
||||
func (Prefix) TableName() string {
|
||||
return "prefix"
|
||||
}
|
||||
|
||||
func UpdatePrefix(guildId int64, prefix string) {
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).Assign(&Prefix{Prefix: prefix}).FirstOrCreate(&Prefix{})
|
||||
}
|
||||
|
||||
func GetPrefix(guildId int64) string {
|
||||
prefix := Prefix{Prefix: "t!"}
|
||||
database.Database.Where(&Prefix{GuildId: guildId}).First(&prefix)
|
||||
|
||||
return prefix.Prefix
|
||||
}
|
||||
|
@ -1,50 +1,50 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketArchive struct {
|
||||
Uuid string `gorm:"column:UUID;type:varchar(36)"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
User int64 `gorm:"column:USERID"`
|
||||
Username string `gorm:"column:USERNAME;type:varchar(32)"`
|
||||
TicketId int `gorm:"column:TICKETID"`
|
||||
CdnUrl string `gorm:"column:CDNURL;type:varchar(100)"`
|
||||
}
|
||||
|
||||
func (TicketArchive) TableName() string {
|
||||
return "ticketarchive"
|
||||
}
|
||||
|
||||
func GetTicketArchives(guildId int64) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
database.Database.Where(&TicketArchive{Guild: guildId}).Order("TICKETID desc").Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
func GetFilteredTicketArchives(guildId int64, userId int64, username string, ticketId int) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
|
||||
query := database.Database.Where(&TicketArchive{Guild: guildId})
|
||||
if userId != 0 {
|
||||
query = query.Where(&TicketArchive{User: userId})
|
||||
}
|
||||
if username != "" {
|
||||
query = query.Where(&TicketArchive{Username: username})
|
||||
}
|
||||
if ticketId != 0 {
|
||||
query = query.Where(&TicketArchive{TicketId: ticketId})
|
||||
}
|
||||
|
||||
query.Order("TICKETID desc").Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
func GetCdnUrl(guildId int64, uuid string) string {
|
||||
var archive TicketArchive
|
||||
database.Database.Where(&TicketArchive{Guild: guildId, Uuid: uuid}).First(&archive)
|
||||
return archive.CdnUrl
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketArchive struct {
|
||||
Uuid string `gorm:"column:UUID;type:varchar(36)"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
User int64 `gorm:"column:USERID"`
|
||||
Username string `gorm:"column:USERNAME;type:varchar(32)"`
|
||||
TicketId int `gorm:"column:TICKETID"`
|
||||
CdnUrl string `gorm:"column:CDNURL;type:varchar(100)"`
|
||||
}
|
||||
|
||||
func (TicketArchive) TableName() string {
|
||||
return "ticketarchive"
|
||||
}
|
||||
|
||||
func GetTicketArchives(guildId int64) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
database.Database.Where(&TicketArchive{Guild: guildId}).Order("TICKETID desc").Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
func GetFilteredTicketArchives(guildId int64, userId int64, username string, ticketId int) []TicketArchive {
|
||||
var archives []TicketArchive
|
||||
|
||||
query := database.Database.Where(&TicketArchive{Guild: guildId})
|
||||
if userId != 0 {
|
||||
query = query.Where(&TicketArchive{User: userId})
|
||||
}
|
||||
if username != "" {
|
||||
query = query.Where(&TicketArchive{Username: username})
|
||||
}
|
||||
if ticketId != 0 {
|
||||
query = query.Where(&TicketArchive{TicketId: ticketId})
|
||||
}
|
||||
|
||||
query.Order("TICKETID desc").Find(&archives)
|
||||
|
||||
return archives
|
||||
}
|
||||
|
||||
func GetCdnUrl(guildId int64, uuid string) string {
|
||||
var archive TicketArchive
|
||||
database.Database.Where(&TicketArchive{Guild: guildId, Uuid: uuid}).First(&archive)
|
||||
return archive.CdnUrl
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketLimit struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Limit int `gorm:"column:TICKETLIMIT"`
|
||||
}
|
||||
|
||||
func (TicketLimit) TableName() string {
|
||||
return "ticketlimit"
|
||||
}
|
||||
|
||||
func UpdateTicketLimit(guildId int64, limit int) {
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).Assign(&TicketLimit{Limit: limit}).FirstOrCreate(&TicketLimit{})
|
||||
}
|
||||
|
||||
func GetTicketLimit(guildId int64) int {
|
||||
limit := TicketLimit{Limit: 5}
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).First(&limit)
|
||||
|
||||
return limit.Limit
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type TicketLimit struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Limit int `gorm:"column:TICKETLIMIT"`
|
||||
}
|
||||
|
||||
func (TicketLimit) TableName() string {
|
||||
return "ticketlimit"
|
||||
}
|
||||
|
||||
func UpdateTicketLimit(guildId int64, limit int) {
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).Assign(&TicketLimit{Limit: limit}).FirstOrCreate(&TicketLimit{})
|
||||
}
|
||||
|
||||
func GetTicketLimit(guildId int64) int {
|
||||
limit := TicketLimit{Limit: 5}
|
||||
database.Database.Where(&TicketLimit{GuildId: guildId}).First(&limit)
|
||||
|
||||
return limit.Limit
|
||||
}
|
||||
|
@ -1,42 +1,42 @@
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type Ticket struct {
|
||||
Uuid string `gorm:"column:UUID;type:varchar(36);primary_key"`
|
||||
TicketId int `gorm:"column:ID"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
Channel int64 `gorm:"column:CHANNELID"`
|
||||
Owner int64 `gorm:"column:OWNERID"`
|
||||
Members string `gorm:"column:MEMBERS;type:text"`
|
||||
IsOpen bool `gorm:"column:OPEN"`
|
||||
OpenTime int64 `gorm:"column:OPENTIME"`
|
||||
}
|
||||
|
||||
func (Ticket) TableName() string {
|
||||
return "tickets"
|
||||
}
|
||||
|
||||
func GetTickets(guild int64) []Ticket {
|
||||
var tickets []Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild}).Order("ID asc").Find(&tickets)
|
||||
return tickets
|
||||
}
|
||||
|
||||
func GetOpenTickets(guild int64) []Ticket {
|
||||
var tickets []Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild, IsOpen: true}).Order("ID asc").Find(&tickets)
|
||||
return tickets
|
||||
}
|
||||
|
||||
func GetTicket(uuid string, ch chan Ticket) {
|
||||
var ticket Ticket
|
||||
database.Database.Where(&Ticket{Uuid: uuid}).First(&ticket)
|
||||
ch <- ticket
|
||||
}
|
||||
|
||||
func GetTicketById(guild int64, id int, ch chan Ticket) {
|
||||
var ticket Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild, TicketId: id}).First(&ticket)
|
||||
ch <- ticket
|
||||
}
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type Ticket struct {
|
||||
Uuid string `gorm:"column:UUID;type:varchar(36);primary_key"`
|
||||
TicketId int `gorm:"column:ID"`
|
||||
Guild int64 `gorm:"column:GUILDID"`
|
||||
Channel int64 `gorm:"column:CHANNELID"`
|
||||
Owner int64 `gorm:"column:OWNERID"`
|
||||
Members string `gorm:"column:MEMBERS;type:text"`
|
||||
IsOpen bool `gorm:"column:OPEN"`
|
||||
OpenTime int64 `gorm:"column:OPENTIME"`
|
||||
}
|
||||
|
||||
func (Ticket) TableName() string {
|
||||
return "tickets"
|
||||
}
|
||||
|
||||
func GetTickets(guild int64) []Ticket {
|
||||
var tickets []Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild}).Order("ID asc").Find(&tickets)
|
||||
return tickets
|
||||
}
|
||||
|
||||
func GetOpenTickets(guild int64) []Ticket {
|
||||
var tickets []Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild, IsOpen: true}).Order("ID asc").Find(&tickets)
|
||||
return tickets
|
||||
}
|
||||
|
||||
func GetTicket(uuid string, ch chan Ticket) {
|
||||
var ticket Ticket
|
||||
database.Database.Where(&Ticket{Uuid: uuid}).First(&ticket)
|
||||
ch <- ticket
|
||||
}
|
||||
|
||||
func GetTicketById(guild int64, id int, ch chan Ticket) {
|
||||
var ticket Ticket
|
||||
database.Database.Where(&Ticket{Guild: guild, TicketId: id}).First(&ticket)
|
||||
ch <- ticket
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type UsernameNode struct {
|
||||
Id int64 `gorm:"column:USERID;primary_key"`
|
||||
Name string `gorm:"column:USERNAME;type:text"` // Base 64 encoded
|
||||
Discriminator string `gorm:"column:DISCRIM;type:varchar(4)"`
|
||||
Avatar string `gorm:"column:AVATARHASH;type:varchar(100)"`
|
||||
}
|
||||
|
||||
func (UsernameNode) TableName() string {
|
||||
return "usernames"
|
||||
}
|
||||
|
||||
func GetUsername(id int64, ch chan string) {
|
||||
node := UsernameNode{Name: "Unknown"}
|
||||
database.Database.Where(&UsernameNode{Id: id}).First(&node)
|
||||
ch <- node.Name
|
||||
}
|
||||
|
||||
func GetUserNodes(ids []int64) []UsernameNode {
|
||||
var nodes []UsernameNode
|
||||
database.Database.Where(ids).Find(&nodes)
|
||||
return nodes
|
||||
}
|
||||
|
||||
func GetUserId(name, discrim string) int64 {
|
||||
var node UsernameNode
|
||||
database.Database.Where(&UsernameNode{Name: name, Discriminator: discrim}).First(&node)
|
||||
return node.Id
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type UsernameNode struct {
|
||||
Id int64 `gorm:"column:USERID;primary_key"`
|
||||
Name string `gorm:"column:USERNAME;type:text"` // Base 64 encoded
|
||||
Discriminator string `gorm:"column:DISCRIM;type:varchar(4)"`
|
||||
Avatar string `gorm:"column:AVATARHASH;type:varchar(100)"`
|
||||
}
|
||||
|
||||
func (UsernameNode) TableName() string {
|
||||
return "usernames"
|
||||
}
|
||||
|
||||
func GetUsername(id int64, ch chan string) {
|
||||
node := UsernameNode{Name: "Unknown"}
|
||||
database.Database.Where(&UsernameNode{Id: id}).First(&node)
|
||||
ch <- node.Name
|
||||
}
|
||||
|
||||
func GetUserNodes(ids []int64) []UsernameNode {
|
||||
var nodes []UsernameNode
|
||||
database.Database.Where(ids).Find(&nodes)
|
||||
return nodes
|
||||
}
|
||||
|
||||
func GetUserId(name, discrim string) int64 {
|
||||
var node UsernameNode
|
||||
database.Database.Where(&UsernameNode{Name: name, Discriminator: discrim}).First(&node)
|
||||
return node.Id
|
||||
}
|
||||
|
@ -1,27 +1,27 @@
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type UserCanClose struct {
|
||||
Guild int64 `gorm:"column:GUILDID;unique;primary_key"`
|
||||
CanClose *bool `gorm:"column:CANCLOSE"`
|
||||
}
|
||||
|
||||
func (UserCanClose) TableName() string {
|
||||
return "usercanclose"
|
||||
}
|
||||
|
||||
func IsUserCanClose(guild int64, ch chan bool) {
|
||||
var node UserCanClose
|
||||
database.Database.Where(UserCanClose{Guild: guild}).First(&node)
|
||||
|
||||
if node.CanClose == nil {
|
||||
ch <- true
|
||||
} else {
|
||||
ch <- *node.CanClose
|
||||
}
|
||||
}
|
||||
|
||||
func SetUserCanClose(guild int64, value bool) {
|
||||
database.Database.Where(&UserCanClose{Guild: guild}).Assign(&UserCanClose{CanClose: &value}).FirstOrCreate(&UserCanClose{})
|
||||
}
|
||||
package table
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/database"
|
||||
|
||||
type UserCanClose struct {
|
||||
Guild int64 `gorm:"column:GUILDID;unique;primary_key"`
|
||||
CanClose *bool `gorm:"column:CANCLOSE"`
|
||||
}
|
||||
|
||||
func (UserCanClose) TableName() string {
|
||||
return "usercanclose"
|
||||
}
|
||||
|
||||
func IsUserCanClose(guild int64, ch chan bool) {
|
||||
var node UserCanClose
|
||||
database.Database.Where(UserCanClose{Guild: guild}).First(&node)
|
||||
|
||||
if node.CanClose == nil {
|
||||
ch <- true
|
||||
} else {
|
||||
ch <- *node.CanClose
|
||||
}
|
||||
}
|
||||
|
||||
func SetUserCanClose(guild int64, value bool) {
|
||||
database.Database.Where(&UserCanClose{Guild: guild}).Assign(&UserCanClose{CanClose: &value}).FirstOrCreate(&UserCanClose{})
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Votes struct {
|
||||
Id int64 `gorm:"type:bigint;unique_index;primary_key"`
|
||||
VoteTime time.Time
|
||||
}
|
||||
|
||||
func (Votes) TableName() string {
|
||||
return "votes"
|
||||
}
|
||||
|
||||
func HasVoted(owner int64, ch chan bool) {
|
||||
var node Votes
|
||||
database.Database.Where(Votes{Id: owner}).First(&node)
|
||||
|
||||
ch <- time.Now().Sub(node.VoteTime) < 24 * time.Hour
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Votes struct {
|
||||
Id int64 `gorm:"type:bigint;unique_index;primary_key"`
|
||||
VoteTime time.Time
|
||||
}
|
||||
|
||||
func (Votes) TableName() string {
|
||||
return "votes"
|
||||
}
|
||||
|
||||
func HasVoted(owner int64, ch chan bool) {
|
||||
var node Votes
|
||||
database.Database.Where(Votes{Id: owner}).First(&node)
|
||||
|
||||
ch <- time.Now().Sub(node.VoteTime) < 24 * time.Hour
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type WelcomeMessage struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Message string `gorm:"column:MESSAGE;type:text"`
|
||||
}
|
||||
|
||||
func (WelcomeMessage) TableName() string {
|
||||
return "welcomemessages"
|
||||
}
|
||||
|
||||
func UpdateWelcomeMessage(guildId int64, message string) {
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).Assign(&WelcomeMessage{Message: message}).FirstOrCreate(&WelcomeMessage{})
|
||||
}
|
||||
|
||||
func GetWelcomeMessage(guildId int64) string {
|
||||
message := WelcomeMessage{Message: "No message specified"}
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).First(&message)
|
||||
|
||||
return message.Message
|
||||
}
|
||||
package table
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/database"
|
||||
)
|
||||
|
||||
type WelcomeMessage struct {
|
||||
GuildId int64 `gorm:"column:GUILDID"`
|
||||
Message string `gorm:"column:MESSAGE;type:text"`
|
||||
}
|
||||
|
||||
func (WelcomeMessage) TableName() string {
|
||||
return "welcomemessages"
|
||||
}
|
||||
|
||||
func UpdateWelcomeMessage(guildId int64, message string) {
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).Assign(&WelcomeMessage{Message: message}).FirstOrCreate(&WelcomeMessage{})
|
||||
}
|
||||
|
||||
func GetWelcomeMessage(guildId int64) string {
|
||||
message := WelcomeMessage{Message: "No message specified"}
|
||||
database.Database.Where(&WelcomeMessage{GuildId: guildId}).First(&message)
|
||||
|
||||
return message.Message
|
||||
}
|
||||
|
3878
emojis.json
3878
emojis.json
File diff suppressed because it is too large
Load Diff
10
public/static/css/animate.min.css
vendored
10
public/static/css/animate.min.css
vendored
File diff suppressed because one or more lines are too long
10
public/static/css/bootstrap.min.css
vendored
10
public/static/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1,69 +1,69 @@
|
||||
@font-face{font-family:Whitney;font-style:light;font-weight:300;src:url('https://discordapp.com/assets/6c6374bad0b0b6d204d8d6dc4a18d820.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:normal;font-weight:500;src:url('https://discordapp.com/assets/e8acd7d9bf6207f99350ca9f9e23b168.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:medium;font-weight:600;src:url('https://discordapp.com/assets/3bdef1251a424500c1b3a78dea9b7e57.woff') format('woff')}
|
||||
@font-face{font-family:WhitneyMedium;font-style:medium;font-weight:600;src:url('https://discordapp.com/assets/be0060dafb7a0e31d2a1ca17c0708636.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:bold;font-weight:700;src:url('https://discordapp.com/assets/8e12fb4f14d9c4592eb8ec9f22337b04.woff') format('woff')}
|
||||
|
||||
.discord-container {
|
||||
background-color: #2e3136;
|
||||
border-radius: 4px;
|
||||
height: 80vh;
|
||||
max-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Whitney', sans-serif !important;
|
||||
}
|
||||
|
||||
.channel-header {
|
||||
background-color: #1e2124;
|
||||
height: 5vh;
|
||||
width: 100%;
|
||||
border-radius: 4px 4px 0 0;
|
||||
position: relative;
|
||||
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
color: white;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#message-container {
|
||||
height: 70vh;
|
||||
max-height: 70vh;
|
||||
position: relative;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: white !important;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
padding-top: 20px !important;
|
||||
border-color: #2e3136 !important;
|
||||
padding-left: 5px !important;
|
||||
padding-right: 5px !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #2e3136 !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.message-input:focus {
|
||||
border-color: #2e3136 !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
}
|
||||
@font-face{font-family:Whitney;font-style:light;font-weight:300;src:url('https://discordapp.com/assets/6c6374bad0b0b6d204d8d6dc4a18d820.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:normal;font-weight:500;src:url('https://discordapp.com/assets/e8acd7d9bf6207f99350ca9f9e23b168.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:medium;font-weight:600;src:url('https://discordapp.com/assets/3bdef1251a424500c1b3a78dea9b7e57.woff') format('woff')}
|
||||
@font-face{font-family:WhitneyMedium;font-style:medium;font-weight:600;src:url('https://discordapp.com/assets/be0060dafb7a0e31d2a1ca17c0708636.woff') format('woff')}
|
||||
@font-face{font-family:Whitney;font-style:bold;font-weight:700;src:url('https://discordapp.com/assets/8e12fb4f14d9c4592eb8ec9f22337b04.woff') format('woff')}
|
||||
|
||||
.discord-container {
|
||||
background-color: #2e3136;
|
||||
border-radius: 4px;
|
||||
height: 80vh;
|
||||
max-height: 100vh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Whitney', sans-serif !important;
|
||||
}
|
||||
|
||||
.channel-header {
|
||||
background-color: #1e2124;
|
||||
height: 5vh;
|
||||
width: 100%;
|
||||
border-radius: 4px 4px 0 0;
|
||||
position: relative;
|
||||
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.channel-name {
|
||||
color: white;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#message-container {
|
||||
height: 70vh;
|
||||
max-height: 70vh;
|
||||
position: relative;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: white !important;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
padding-top: 20px !important;
|
||||
border-color: #2e3136 !important;
|
||||
padding-left: 5px !important;
|
||||
padding-right: 5px !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #2e3136 !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.message-input:focus {
|
||||
border-color: #2e3136 !important;
|
||||
background-color: #2e3136 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
7738
public/static/css/light-bootstrap-dashboard.css
vendored
7738
public/static/css/light-bootstrap-dashboard.css
vendored
File diff suppressed because it is too large
Load Diff
@ -1,39 +1,39 @@
|
||||
body {
|
||||
font-family: 'Open Sans',sans-serif !important;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background: url("/assets/img/sidebar-2.jpg");
|
||||
background-size: cover;
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.sidebar-bottom {
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.filterCard {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table td, .table th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close-container {
|
||||
text-align: right;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.input-fill {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
body {
|
||||
font-family: 'Open Sans',sans-serif !important;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background: url("/assets/img/sidebar-2.jpg");
|
||||
background-size: cover;
|
||||
overflow-x: hidden !important;
|
||||
}
|
||||
|
||||
.sidebar-bottom {
|
||||
position: absolute !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.filterCard {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.table td, .table th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.close-container {
|
||||
text-align: right;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.input-fill {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
|
||||
<circle transform="translate(8 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(16 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.3"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(24 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.6"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
|
||||
<circle transform="translate(8 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(16 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.3"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
<circle transform="translate(24 0)" cx="0" cy="16" r="0">
|
||||
<animate attributeName="r" values="0; 4; 0; 0" dur="1.2s" repeatCount="indefinite" begin="0.6"
|
||||
keytimes="0;0.2;0.7;1" keySplines="0.2 0.2 0.4 0.8;0.2 0.6 0.4 0.8;0.2 0.6 0.4 0.8" calcMode="spline" />
|
||||
</circle>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 950 B After Width: | Height: | Size: 964 B |
808
public/static/js/bootstrap-notify.js
vendored
808
public/static/js/bootstrap-notify.js
vendored
@ -1,404 +1,404 @@
|
||||
/*
|
||||
|
||||
|
||||
|
||||
Creative Tim Modifications
|
||||
|
||||
Lines: 239, 240 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
|
||||
Line:242 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Project: Bootstrap Notify = v3.1.5
|
||||
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
|
||||
* Author: Mouse0270 aka Robert McIntosh
|
||||
* License: MIT License
|
||||
* Website: https://github.com/mouse0270/bootstrap-growl
|
||||
*/
|
||||
|
||||
/* global define:false, require: false, jQuery:false */
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
// Create the defaults once
|
||||
var defaults = {
|
||||
element: 'body',
|
||||
position: null,
|
||||
type: "info",
|
||||
allow_dismiss: true,
|
||||
allow_duplicates: true,
|
||||
newest_on_top: false,
|
||||
showProgressbar: false,
|
||||
placement: {
|
||||
from: "top",
|
||||
align: "right"
|
||||
},
|
||||
offset: 20,
|
||||
spacing: 10,
|
||||
z_index: 1031,
|
||||
delay: 5000,
|
||||
timer: 1000,
|
||||
url_target: '_blank',
|
||||
mouse_over: null,
|
||||
animate: {
|
||||
enter: 'animated fadeInDown',
|
||||
exit: 'animated fadeOutUp'
|
||||
},
|
||||
onShow: null,
|
||||
onShown: null,
|
||||
onClose: null,
|
||||
onClosed: null,
|
||||
icon_type: 'class',
|
||||
template: '<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
|
||||
};
|
||||
|
||||
String.format = function () {
|
||||
var str = arguments[0];
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
str = str.replace(RegExp("\\{" + (i - 1) + "\\}", "gm"), arguments[i]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
function isDuplicateNotification(notification) {
|
||||
var isDupe = false;
|
||||
|
||||
$('[data-notify="container"]').each(function (i, el) {
|
||||
var $el = $(el);
|
||||
var title = $el.find('[data-notify="title"]').text().trim();
|
||||
var message = $el.find('[data-notify="message"]').html().trim();
|
||||
|
||||
// The input string might be different than the actual parsed HTML string!
|
||||
// (<br> vs <br /> for example)
|
||||
// So we have to force-parse this as HTML here!
|
||||
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
|
||||
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
|
||||
var isSameType = $el.hasClass('alert-' + notification.settings.type);
|
||||
|
||||
if (isSameTitle && isSameMsg && isSameType) {
|
||||
//we found the dupe. Set the var and stop checking.
|
||||
isDupe = true;
|
||||
}
|
||||
return !isDupe;
|
||||
});
|
||||
|
||||
return isDupe;
|
||||
}
|
||||
|
||||
function Notify(element, content, options) {
|
||||
// Setup Content of Notify
|
||||
var contentObj = {
|
||||
content: {
|
||||
message: typeof content === 'object' ? content.message : content,
|
||||
title: content.title ? content.title : '',
|
||||
icon: content.icon ? content.icon : '',
|
||||
url: content.url ? content.url : '#',
|
||||
target: content.target ? content.target : '-'
|
||||
}
|
||||
};
|
||||
|
||||
options = $.extend(true, {}, contentObj, options);
|
||||
this.settings = $.extend(true, {}, defaults, options);
|
||||
this._defaults = defaults;
|
||||
if (this.settings.content.target === "-") {
|
||||
this.settings.content.target = this.settings.url_target;
|
||||
}
|
||||
this.animations = {
|
||||
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
|
||||
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
|
||||
};
|
||||
|
||||
if (typeof this.settings.offset === 'number') {
|
||||
this.settings.offset = {
|
||||
x: this.settings.offset,
|
||||
y: this.settings.offset
|
||||
};
|
||||
}
|
||||
|
||||
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
|
||||
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(Notify.prototype, {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this.buildNotify();
|
||||
if (this.settings.content.icon) {
|
||||
this.setIcon();
|
||||
}
|
||||
if (this.settings.content.url != "#") {
|
||||
this.styleURL();
|
||||
}
|
||||
this.styleDismiss();
|
||||
this.placement();
|
||||
this.bind();
|
||||
|
||||
this.notify = {
|
||||
$ele: this.$ele,
|
||||
update: function (command, update) {
|
||||
var commands = {};
|
||||
if (typeof command === "string") {
|
||||
commands[command] = update;
|
||||
} else {
|
||||
commands = command;
|
||||
}
|
||||
for (var cmd in commands) {
|
||||
switch (cmd) {
|
||||
case "type":
|
||||
this.$ele.removeClass('alert-' + self.settings.type);
|
||||
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
|
||||
self.settings.type = commands[cmd];
|
||||
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
|
||||
break;
|
||||
case "icon":
|
||||
var $icon = this.$ele.find('[data-notify="icon"]');
|
||||
if (self.settings.icon_type.toLowerCase() === 'class') {
|
||||
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
|
||||
} else {
|
||||
if (!$icon.is('img')) {
|
||||
$icon.find('img');
|
||||
}
|
||||
$icon.attr('src', commands[cmd]);
|
||||
}
|
||||
break;
|
||||
case "progress":
|
||||
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
|
||||
this.$ele.data('notify-delay', newDelay);
|
||||
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
|
||||
break;
|
||||
case "url":
|
||||
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
|
||||
break;
|
||||
case "target":
|
||||
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
|
||||
break;
|
||||
default:
|
||||
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
|
||||
}
|
||||
}
|
||||
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
|
||||
self.reposition(posX);
|
||||
},
|
||||
close: function () {
|
||||
self.close();
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
buildNotify: function () {
|
||||
var content = this.settings.content;
|
||||
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
|
||||
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
|
||||
if (!this.settings.allow_dismiss) {
|
||||
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
|
||||
}
|
||||
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
|
||||
this.$ele.find('[data-notify="progressbar"]').remove();
|
||||
}
|
||||
},
|
||||
setIcon: function () {
|
||||
|
||||
this.$ele.addClass('alert-with-icon');
|
||||
|
||||
if (this.settings.icon_type.toLowerCase() === 'class') {
|
||||
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
|
||||
} else {
|
||||
if (this.$ele.find('[data-notify="icon"]').is('img')) {
|
||||
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
|
||||
} else {
|
||||
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
|
||||
}
|
||||
}
|
||||
},
|
||||
styleDismiss: function () {
|
||||
this.$ele.find('[data-notify="dismiss"]').css({
|
||||
position: 'absolute',
|
||||
right: '10px',
|
||||
top: '50%',
|
||||
marginTop: '-13px',
|
||||
zIndex: this.settings.z_index + 2
|
||||
});
|
||||
},
|
||||
styleURL: function () {
|
||||
this.$ele.find('[data-notify="url"]').css({
|
||||
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
|
||||
height: '100%',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: '100%',
|
||||
zIndex: this.settings.z_index + 1
|
||||
});
|
||||
},
|
||||
placement: function () {
|
||||
var self = this,
|
||||
offsetAmt = this.settings.offset.y,
|
||||
css = {
|
||||
display: 'inline-block',
|
||||
margin: '0px auto',
|
||||
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
|
||||
transition: 'all .5s ease-in-out',
|
||||
zIndex: this.settings.z_index
|
||||
},
|
||||
hasAnimation = false,
|
||||
settings = this.settings;
|
||||
|
||||
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () {
|
||||
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
|
||||
});
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = this.settings.offset.y;
|
||||
}
|
||||
css[this.settings.placement.from] = offsetAmt + 'px';
|
||||
|
||||
switch (this.settings.placement.align) {
|
||||
case "left":
|
||||
case "right":
|
||||
css[this.settings.placement.align] = this.settings.offset.x + 'px';
|
||||
break;
|
||||
case "center":
|
||||
css.left = 0;
|
||||
css.right = 0;
|
||||
break;
|
||||
}
|
||||
this.$ele.css(css).addClass(this.settings.animate.enter);
|
||||
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) {
|
||||
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
|
||||
});
|
||||
|
||||
$(this.settings.element).append(this.$ele);
|
||||
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
|
||||
this.reposition(offsetAmt);
|
||||
}
|
||||
|
||||
if ($.isFunction(self.settings.onShow)) {
|
||||
self.settings.onShow.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
bind: function () {
|
||||
var self = this;
|
||||
|
||||
this.$ele.find('[data-notify="dismiss"]').on('click', function () {
|
||||
self.close();
|
||||
});
|
||||
|
||||
this.$ele.mouseover(function () {
|
||||
$(this).data('data-hover', "true");
|
||||
}).mouseout(function () {
|
||||
$(this).data('data-hover', "false");
|
||||
});
|
||||
this.$ele.data('data-hover', "false");
|
||||
|
||||
if (this.settings.delay > 0) {
|
||||
self.$ele.data('notify-delay', self.settings.delay);
|
||||
var timer = setInterval(function () {
|
||||
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
|
||||
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
|
||||
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
|
||||
self.$ele.data('notify-delay', delay);
|
||||
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
|
||||
}
|
||||
if (delay <= -(self.settings.timer)) {
|
||||
clearInterval(timer);
|
||||
self.close();
|
||||
}
|
||||
}, self.settings.timer);
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = this,
|
||||
posX = parseInt(this.$ele.css(this.settings.placement.from)),
|
||||
hasAnimation = false;
|
||||
|
||||
this.$ele.data('closing', 'true').addClass(this.settings.animate.exit);
|
||||
self.reposition(posX);
|
||||
|
||||
if ($.isFunction(self.settings.onClose)) {
|
||||
self.settings.onClose.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
$(this).remove();
|
||||
if ($.isFunction(self.settings.onClosed)) {
|
||||
self.settings.onClosed.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
self.$ele.remove();
|
||||
if (self.settings.onClosed) {
|
||||
self.settings.onClosed(self.$ele);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
reposition: function (posX) {
|
||||
var self = this,
|
||||
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
|
||||
$elements = this.$ele.nextAll(notifies);
|
||||
if (this.settings.newest_on_top === true) {
|
||||
$elements = this.$ele.prevAll(notifies);
|
||||
}
|
||||
$elements.each(function () {
|
||||
$(this).css(self.settings.placement.from, posX);
|
||||
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.notify = function (content, options) {
|
||||
var plugin = new Notify(this, content, options);
|
||||
return plugin.notify;
|
||||
};
|
||||
$.notifyDefaults = function (options) {
|
||||
defaults = $.extend(true, {}, defaults, options);
|
||||
return defaults;
|
||||
};
|
||||
$.notifyClose = function (command) {
|
||||
if (typeof command === "undefined" || command === "all") {
|
||||
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
|
||||
} else {
|
||||
$('[data-notify-position="' + command + '"]').find('[data-notify="dismiss"]').trigger('click');
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
||||
/*
|
||||
|
||||
|
||||
|
||||
Creative Tim Modifications
|
||||
|
||||
Lines: 239, 240 was changed from top: 5px to top: 50% and we added margin-top: -13px. In this way the close button will be aligned vertically
|
||||
Line:242 - modified when the icon is set, we add the class "alert-with-icon", so there will be enough space for the icon.
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Project: Bootstrap Notify = v3.1.5
|
||||
* Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
|
||||
* Author: Mouse0270 aka Robert McIntosh
|
||||
* License: MIT License
|
||||
* Website: https://github.com/mouse0270/bootstrap-growl
|
||||
*/
|
||||
|
||||
/* global define:false, require: false, jQuery:false */
|
||||
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node/CommonJS
|
||||
factory(require('jquery'));
|
||||
} else {
|
||||
// Browser globals
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
// Create the defaults once
|
||||
var defaults = {
|
||||
element: 'body',
|
||||
position: null,
|
||||
type: "info",
|
||||
allow_dismiss: true,
|
||||
allow_duplicates: true,
|
||||
newest_on_top: false,
|
||||
showProgressbar: false,
|
||||
placement: {
|
||||
from: "top",
|
||||
align: "right"
|
||||
},
|
||||
offset: 20,
|
||||
spacing: 10,
|
||||
z_index: 1031,
|
||||
delay: 5000,
|
||||
timer: 1000,
|
||||
url_target: '_blank',
|
||||
mouse_over: null,
|
||||
animate: {
|
||||
enter: 'animated fadeInDown',
|
||||
exit: 'animated fadeOutUp'
|
||||
},
|
||||
onShow: null,
|
||||
onShown: null,
|
||||
onClose: null,
|
||||
onClosed: null,
|
||||
icon_type: 'class',
|
||||
template: '<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
|
||||
};
|
||||
|
||||
String.format = function () {
|
||||
var str = arguments[0];
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
str = str.replace(RegExp("\\{" + (i - 1) + "\\}", "gm"), arguments[i]);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
function isDuplicateNotification(notification) {
|
||||
var isDupe = false;
|
||||
|
||||
$('[data-notify="container"]').each(function (i, el) {
|
||||
var $el = $(el);
|
||||
var title = $el.find('[data-notify="title"]').text().trim();
|
||||
var message = $el.find('[data-notify="message"]').html().trim();
|
||||
|
||||
// The input string might be different than the actual parsed HTML string!
|
||||
// (<br> vs <br /> for example)
|
||||
// So we have to force-parse this as HTML here!
|
||||
var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
|
||||
var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
|
||||
var isSameType = $el.hasClass('alert-' + notification.settings.type);
|
||||
|
||||
if (isSameTitle && isSameMsg && isSameType) {
|
||||
//we found the dupe. Set the var and stop checking.
|
||||
isDupe = true;
|
||||
}
|
||||
return !isDupe;
|
||||
});
|
||||
|
||||
return isDupe;
|
||||
}
|
||||
|
||||
function Notify(element, content, options) {
|
||||
// Setup Content of Notify
|
||||
var contentObj = {
|
||||
content: {
|
||||
message: typeof content === 'object' ? content.message : content,
|
||||
title: content.title ? content.title : '',
|
||||
icon: content.icon ? content.icon : '',
|
||||
url: content.url ? content.url : '#',
|
||||
target: content.target ? content.target : '-'
|
||||
}
|
||||
};
|
||||
|
||||
options = $.extend(true, {}, contentObj, options);
|
||||
this.settings = $.extend(true, {}, defaults, options);
|
||||
this._defaults = defaults;
|
||||
if (this.settings.content.target === "-") {
|
||||
this.settings.content.target = this.settings.url_target;
|
||||
}
|
||||
this.animations = {
|
||||
start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
|
||||
end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
|
||||
};
|
||||
|
||||
if (typeof this.settings.offset === 'number') {
|
||||
this.settings.offset = {
|
||||
x: this.settings.offset,
|
||||
y: this.settings.offset
|
||||
};
|
||||
}
|
||||
|
||||
//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
|
||||
if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
|
||||
$.extend(Notify.prototype, {
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this.buildNotify();
|
||||
if (this.settings.content.icon) {
|
||||
this.setIcon();
|
||||
}
|
||||
if (this.settings.content.url != "#") {
|
||||
this.styleURL();
|
||||
}
|
||||
this.styleDismiss();
|
||||
this.placement();
|
||||
this.bind();
|
||||
|
||||
this.notify = {
|
||||
$ele: this.$ele,
|
||||
update: function (command, update) {
|
||||
var commands = {};
|
||||
if (typeof command === "string") {
|
||||
commands[command] = update;
|
||||
} else {
|
||||
commands = command;
|
||||
}
|
||||
for (var cmd in commands) {
|
||||
switch (cmd) {
|
||||
case "type":
|
||||
this.$ele.removeClass('alert-' + self.settings.type);
|
||||
this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
|
||||
self.settings.type = commands[cmd];
|
||||
this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
|
||||
break;
|
||||
case "icon":
|
||||
var $icon = this.$ele.find('[data-notify="icon"]');
|
||||
if (self.settings.icon_type.toLowerCase() === 'class') {
|
||||
$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
|
||||
} else {
|
||||
if (!$icon.is('img')) {
|
||||
$icon.find('img');
|
||||
}
|
||||
$icon.attr('src', commands[cmd]);
|
||||
}
|
||||
break;
|
||||
case "progress":
|
||||
var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
|
||||
this.$ele.data('notify-delay', newDelay);
|
||||
this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
|
||||
break;
|
||||
case "url":
|
||||
this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
|
||||
break;
|
||||
case "target":
|
||||
this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
|
||||
break;
|
||||
default:
|
||||
this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
|
||||
}
|
||||
}
|
||||
var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
|
||||
self.reposition(posX);
|
||||
},
|
||||
close: function () {
|
||||
self.close();
|
||||
}
|
||||
};
|
||||
|
||||
},
|
||||
buildNotify: function () {
|
||||
var content = this.settings.content;
|
||||
this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
|
||||
this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
|
||||
if (!this.settings.allow_dismiss) {
|
||||
this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
|
||||
}
|
||||
if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
|
||||
this.$ele.find('[data-notify="progressbar"]').remove();
|
||||
}
|
||||
},
|
||||
setIcon: function () {
|
||||
|
||||
this.$ele.addClass('alert-with-icon');
|
||||
|
||||
if (this.settings.icon_type.toLowerCase() === 'class') {
|
||||
this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
|
||||
} else {
|
||||
if (this.$ele.find('[data-notify="icon"]').is('img')) {
|
||||
this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
|
||||
} else {
|
||||
this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
|
||||
}
|
||||
}
|
||||
},
|
||||
styleDismiss: function () {
|
||||
this.$ele.find('[data-notify="dismiss"]').css({
|
||||
position: 'absolute',
|
||||
right: '10px',
|
||||
top: '50%',
|
||||
marginTop: '-13px',
|
||||
zIndex: this.settings.z_index + 2
|
||||
});
|
||||
},
|
||||
styleURL: function () {
|
||||
this.$ele.find('[data-notify="url"]').css({
|
||||
backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
|
||||
height: '100%',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
width: '100%',
|
||||
zIndex: this.settings.z_index + 1
|
||||
});
|
||||
},
|
||||
placement: function () {
|
||||
var self = this,
|
||||
offsetAmt = this.settings.offset.y,
|
||||
css = {
|
||||
display: 'inline-block',
|
||||
margin: '0px auto',
|
||||
position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
|
||||
transition: 'all .5s ease-in-out',
|
||||
zIndex: this.settings.z_index
|
||||
},
|
||||
hasAnimation = false,
|
||||
settings = this.settings;
|
||||
|
||||
$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () {
|
||||
offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
|
||||
});
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = this.settings.offset.y;
|
||||
}
|
||||
css[this.settings.placement.from] = offsetAmt + 'px';
|
||||
|
||||
switch (this.settings.placement.align) {
|
||||
case "left":
|
||||
case "right":
|
||||
css[this.settings.placement.align] = this.settings.offset.x + 'px';
|
||||
break;
|
||||
case "center":
|
||||
css.left = 0;
|
||||
css.right = 0;
|
||||
break;
|
||||
}
|
||||
this.$ele.css(css).addClass(this.settings.animate.enter);
|
||||
$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) {
|
||||
self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
|
||||
});
|
||||
|
||||
$(this.settings.element).append(this.$ele);
|
||||
|
||||
if (this.settings.newest_on_top === true) {
|
||||
offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
|
||||
this.reposition(offsetAmt);
|
||||
}
|
||||
|
||||
if ($.isFunction(self.settings.onShow)) {
|
||||
self.settings.onShow.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
if ($.isFunction(self.settings.onShown)) {
|
||||
self.settings.onShown.call(this);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
bind: function () {
|
||||
var self = this;
|
||||
|
||||
this.$ele.find('[data-notify="dismiss"]').on('click', function () {
|
||||
self.close();
|
||||
});
|
||||
|
||||
this.$ele.mouseover(function () {
|
||||
$(this).data('data-hover', "true");
|
||||
}).mouseout(function () {
|
||||
$(this).data('data-hover', "false");
|
||||
});
|
||||
this.$ele.data('data-hover', "false");
|
||||
|
||||
if (this.settings.delay > 0) {
|
||||
self.$ele.data('notify-delay', self.settings.delay);
|
||||
var timer = setInterval(function () {
|
||||
var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
|
||||
if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
|
||||
var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
|
||||
self.$ele.data('notify-delay', delay);
|
||||
self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
|
||||
}
|
||||
if (delay <= -(self.settings.timer)) {
|
||||
clearInterval(timer);
|
||||
self.close();
|
||||
}
|
||||
}, self.settings.timer);
|
||||
}
|
||||
},
|
||||
close: function () {
|
||||
var self = this,
|
||||
posX = parseInt(this.$ele.css(this.settings.placement.from)),
|
||||
hasAnimation = false;
|
||||
|
||||
this.$ele.data('closing', 'true').addClass(this.settings.animate.exit);
|
||||
self.reposition(posX);
|
||||
|
||||
if ($.isFunction(self.settings.onClose)) {
|
||||
self.settings.onClose.call(this.$ele);
|
||||
}
|
||||
|
||||
this.$ele.one(this.animations.start, function () {
|
||||
hasAnimation = true;
|
||||
}).one(this.animations.end, function () {
|
||||
$(this).remove();
|
||||
if ($.isFunction(self.settings.onClosed)) {
|
||||
self.settings.onClosed.call(this);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(function () {
|
||||
if (!hasAnimation) {
|
||||
self.$ele.remove();
|
||||
if (self.settings.onClosed) {
|
||||
self.settings.onClosed(self.$ele);
|
||||
}
|
||||
}
|
||||
}, 600);
|
||||
},
|
||||
reposition: function (posX) {
|
||||
var self = this,
|
||||
notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
|
||||
$elements = this.$ele.nextAll(notifies);
|
||||
if (this.settings.newest_on_top === true) {
|
||||
$elements = this.$ele.prevAll(notifies);
|
||||
}
|
||||
$elements.each(function () {
|
||||
$(this).css(self.settings.placement.from, posX);
|
||||
posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$.notify = function (content, options) {
|
||||
var plugin = new Notify(this, content, options);
|
||||
return plugin.notify;
|
||||
};
|
||||
$.notifyDefaults = function (options) {
|
||||
defaults = $.extend(true, {}, defaults, options);
|
||||
return defaults;
|
||||
};
|
||||
$.notifyClose = function (command) {
|
||||
if (typeof command === "undefined" || command === "all") {
|
||||
$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
|
||||
} else {
|
||||
$('[data-notify-position="' + command + '"]').find('[data-notify="dismiss"]').trigger('click');
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
||||
|
876
public/static/js/bootstrap-select.js
vendored
876
public/static/js/bootstrap-select.js
vendored
@ -1,438 +1,438 @@
|
||||
!function($) {
|
||||
var Selectpicker = function(element, options, e) {
|
||||
if (e ) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this.$element = $(element);
|
||||
this.$newElement = null;
|
||||
this.button = null;
|
||||
|
||||
//Merge defaults, options and data-attributes to make our options
|
||||
this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options);
|
||||
|
||||
//If we have no title yet, check the attribute 'title' (this is missed by jq as its not a data-attribute
|
||||
if(this.options.title==null)
|
||||
this.options.title = this.$element.attr('title');
|
||||
|
||||
//Expose public methods
|
||||
this.val = Selectpicker.prototype.val;
|
||||
this.render = Selectpicker.prototype.render;
|
||||
this.init();
|
||||
};
|
||||
|
||||
Selectpicker.prototype = {
|
||||
|
||||
constructor: Selectpicker,
|
||||
|
||||
init: function (e) {
|
||||
var _this = this;
|
||||
this.$element.hide();
|
||||
this.multiple = this.$element.prop('multiple');
|
||||
|
||||
|
||||
var classList = this.$element.attr('class') !== undefined ? this.$element.attr('class').split(/\s+/) : '';
|
||||
var id = this.$element.attr('id');
|
||||
this.$element.after( this.createView() );
|
||||
this.$newElement = this.$element.next('.select');
|
||||
var select = this.$newElement;
|
||||
var menu = this.$newElement.find('.dropdown-menu');
|
||||
var menuArrow = this.$newElement.find('.dropdown-arrow');
|
||||
var menuA = menu.find('li > a');
|
||||
var liHeight = select.addClass('open').find('.dropdown-menu li > a').outerHeight();
|
||||
select.removeClass('open');
|
||||
var divHeight = menu.find('li .divider').outerHeight(true);
|
||||
var selectOffset_top = this.$newElement.offset().top;
|
||||
var size = 0;
|
||||
var menuHeight = 0;
|
||||
var selectHeight = this.$newElement.outerHeight();
|
||||
this.button = this.$newElement.find('> button');
|
||||
if (id !== undefined) {
|
||||
this.button.attr('id', id);
|
||||
$('label[for="' + id + '"]').click(function(){ select.find('button#'+id).focus(); })
|
||||
}
|
||||
for (var i = 0; i < classList.length; i++) {
|
||||
if(classList[i] != 'selectpicker') {
|
||||
this.$newElement.addClass(classList[i]);
|
||||
}
|
||||
}
|
||||
//If we are multiple, then add the show-tick class by default
|
||||
if(this.multiple) {
|
||||
this.$newElement.addClass('select-multiple');
|
||||
}
|
||||
this.button.addClass(this.options.style);
|
||||
menu.addClass(this.options.menuStyle);
|
||||
menuArrow.addClass(function() {
|
||||
if (_this.options.menuStyle) {
|
||||
return _this.options.menuStyle.replace('dropdown-', 'dropdown-arrow-');
|
||||
}
|
||||
});
|
||||
this.checkDisabled();
|
||||
this.checkTabIndex();
|
||||
this.clickListener();
|
||||
var menuPadding = parseInt(menu.css('padding-top')) + parseInt(menu.css('padding-bottom')) + parseInt(menu.css('border-top-width')) + parseInt(menu.css('border-bottom-width'));
|
||||
if (this.options.size == 'auto') {
|
||||
|
||||
// Creative Tim Changes: We changed the regular function made in bootstrap-select with this function so the getSize() will not be triggered one million times per second while you scroll.
|
||||
|
||||
var getSize = debounce(function() {
|
||||
var selectOffset_top_scroll = selectOffset_top - $(window).scrollTop();
|
||||
var windowHeight = $(window).innerHeight();
|
||||
var menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2;
|
||||
var selectOffset_bot = windowHeight - selectOffset_top_scroll - selectHeight - menuExtras;
|
||||
menuHeight = selectOffset_bot;
|
||||
if (select.hasClass('dropup')) {
|
||||
menuHeight = selectOffset_top_scroll - menuExtras;
|
||||
}
|
||||
//limit menuHeight to 300px to have a smooth transition with cubic bezier on dropdown
|
||||
if(menuHeight >= 300){
|
||||
menuHeight = 300;
|
||||
}
|
||||
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'auto', 'min-height' : liHeight * 3 + 'px'});
|
||||
|
||||
}, 50);
|
||||
|
||||
getSize;
|
||||
$(window).on('scroll', getSize);
|
||||
$(window).on('resize', getSize);
|
||||
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver(getSize).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', getSize);
|
||||
}
|
||||
} else if (this.options.size && this.options.size != 'auto' && menu.find('li').length > this.options.size) {
|
||||
var optIndex = menu.find("li > *").filter(':not(.divider)').slice(0,this.options.size).last().parent().index();
|
||||
var divLength = menu.find("li").slice(0,optIndex + 1).find('.divider').length;
|
||||
menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding;
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'scroll'});
|
||||
//console.log('sunt in if');
|
||||
}
|
||||
|
||||
// Listen for updates to the DOM and re render... (Use Mutation Observer when availiable)
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver($.proxy(this.reloadLi, this)).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', $.proxy(this.reloadLi, this));
|
||||
}
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
createDropdown: function() {
|
||||
var drop =
|
||||
"<div class='btn-group select'>" +
|
||||
"<button class='btn dropdown-toggle clearfix' data-toggle='dropdown'>" +
|
||||
"<span class='filter-option'></span> " +
|
||||
"<span class='caret'></span>" +
|
||||
"</button>" +
|
||||
"<span class='dropdown-arrow'></span>" +
|
||||
"<ul class='dropdown-menu' role='menu'>" +
|
||||
"</ul>" +
|
||||
"</div>";
|
||||
|
||||
return $(drop);
|
||||
},
|
||||
|
||||
|
||||
createView: function() {
|
||||
var $drop = this.createDropdown();
|
||||
var $li = this.createLi();
|
||||
$drop.find('ul').append($li);
|
||||
return $drop;
|
||||
},
|
||||
|
||||
reloadLi: function() {
|
||||
//Remove all children.
|
||||
this.destroyLi();
|
||||
//Re build
|
||||
$li = this.createLi();
|
||||
this.$newElement.find('ul').append( $li );
|
||||
//render view
|
||||
this.render();
|
||||
},
|
||||
|
||||
destroyLi:function() {
|
||||
this.$newElement.find('li').remove();
|
||||
},
|
||||
|
||||
createLi: function() {
|
||||
|
||||
var _this = this;
|
||||
var _li = [];
|
||||
var _liA = [];
|
||||
var _liHtml = '';
|
||||
|
||||
this.$element.find('option').each(function(){
|
||||
_li.push($(this).text());
|
||||
});
|
||||
|
||||
this.$element.find('option').each(function(index) {
|
||||
//Get the class and text for the option
|
||||
var optionClass = $(this).attr("class") !== undefined ? $(this).attr("class") : '';
|
||||
var text = $(this).text();
|
||||
var subtext = $(this).data('subtext') !== undefined ? '<small class="muted">'+$(this).data('subtext')+'</small>' : '';
|
||||
|
||||
//Append any subtext to the main text.
|
||||
text+=subtext;
|
||||
|
||||
if ($(this).parent().is('optgroup') && $(this).data('divider') != true) {
|
||||
if ($(this).index() == 0) {
|
||||
//Get the opt group label
|
||||
var label = $(this).parent().attr('label');
|
||||
var labelSubtext = $(this).parent().data('subtext') !== undefined ? '<small class="muted">'+$(this).parent().data('subtext')+'</small>' : '';
|
||||
label += labelSubtext;
|
||||
|
||||
if ($(this)[0].index != 0) {
|
||||
_liA.push(
|
||||
'<div class="divider"></div>'+
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass )
|
||||
);
|
||||
} else {
|
||||
_liA.push(
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass ));
|
||||
}
|
||||
} else {
|
||||
_liA.push( _this.createA(text, "opt " + optionClass ) );
|
||||
}
|
||||
} else if ($(this).data('divider') == true) {
|
||||
_liA.push('<div class="divider"></div>');
|
||||
} else if ($(this).data('hidden') == true) {
|
||||
_liA.push('');
|
||||
} else {
|
||||
_liA.push( _this.createA(text, optionClass ) );
|
||||
}
|
||||
});
|
||||
|
||||
if (_li.length > 0) {
|
||||
for (var i = 0; i < _li.length; i++) {
|
||||
var $option = this.$element.find('option').eq(i);
|
||||
_liHtml += "<li rel=" + i + ">" + _liA[i] + "</li>";
|
||||
}
|
||||
}
|
||||
|
||||
//If we dont have a selected item, and we dont have a title, select the first element so something is set in the button
|
||||
if(this.$element.find('option:selected').length==0 && !_this.options.title) {
|
||||
this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
|
||||
return $(_liHtml);
|
||||
},
|
||||
|
||||
createA:function(test, classes) {
|
||||
return '<a tabindex="-1" href="#" class="'+classes+'">' +
|
||||
'<span class="">' + test + '</span>' +
|
||||
'</a>';
|
||||
|
||||
},
|
||||
|
||||
render:function() {
|
||||
var _this = this;
|
||||
|
||||
//Set width of select
|
||||
if (this.options.width == 'auto') {
|
||||
var ulWidth = this.$newElement.find('.dropdown-menu').css('width');
|
||||
this.$newElement.css('width',ulWidth);
|
||||
} else if (this.options.width && this.options.width != 'auto') {
|
||||
this.$newElement.css('width',this.options.width);
|
||||
}
|
||||
|
||||
//Update the LI to match the SELECT
|
||||
this.$element.find('option').each(function(index) {
|
||||
_this.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') );
|
||||
_this.setSelected(index, $(this).is(':selected') );
|
||||
});
|
||||
|
||||
|
||||
|
||||
var selectedItems = this.$element.find('option:selected').map(function(index,value) {
|
||||
if($(this).attr('title')!=undefined) {
|
||||
return $(this).attr('title');
|
||||
} else {
|
||||
return $(this).text();
|
||||
}
|
||||
}).toArray();
|
||||
|
||||
//Convert all the values into a comma delimited string
|
||||
var title = selectedItems.join(", ");
|
||||
|
||||
//If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
|
||||
if(_this.multiple && _this.options.selectedTextFormat.indexOf('count') > -1) {
|
||||
var max = _this.options.selectedTextFormat.split(">");
|
||||
if( (max.length>1 && selectedItems.length > max[1]) || (max.length==1 && selectedItems.length>=2)) {
|
||||
title = selectedItems.length +' of ' + this.$element.find('option').length + ' selected';
|
||||
}
|
||||
}
|
||||
|
||||
//If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
|
||||
if(!title) {
|
||||
title = _this.options.title != undefined ? _this.options.title : _this.options.noneSelectedText;
|
||||
}
|
||||
|
||||
this.$element.next('.select').find('.filter-option').html( title );
|
||||
},
|
||||
|
||||
|
||||
|
||||
setSelected:function(index, selected) {
|
||||
if(selected) {
|
||||
this.$newElement.find('li').eq(index).addClass('selected');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('selected');
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled:function(index, disabled) {
|
||||
if(disabled) {
|
||||
this.$newElement.find('li').eq(index).addClass('disabled');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
checkDisabled: function() {
|
||||
if (this.$element.is(':disabled')) {
|
||||
this.button.addClass('disabled');
|
||||
this.button.click(function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
checkTabIndex: function() {
|
||||
if (this.$element.is('[tabindex]')) {
|
||||
var tabindex = this.$element.attr("tabindex");
|
||||
this.button.attr('tabindex', tabindex);
|
||||
}
|
||||
},
|
||||
|
||||
clickListener: function() {
|
||||
var _this = this;
|
||||
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
|
||||
|
||||
|
||||
this.$newElement.on('click', 'li a', function(e){
|
||||
var clickedIndex = $(this).parent().index(),
|
||||
$this = $(this).parent(),
|
||||
$select = $this.parents('.select');
|
||||
|
||||
|
||||
//Dont close on multi choice menu
|
||||
if(_this.multiple) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
//Dont run if we have been disabled
|
||||
if ($select.prev('select').not(':disabled') && !$(this).parent().hasClass('disabled')){
|
||||
//Deselect all others if not multi select box
|
||||
if (!_this.multiple) {
|
||||
$select.prev('select').find('option').removeAttr('selected');
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
//Else toggle the one we have chosen if we are multi selet.
|
||||
else {
|
||||
var selected = $select.prev('select').find('option').eq(clickedIndex).prop('selected');
|
||||
|
||||
if(selected) {
|
||||
$select.prev('select').find('option').eq(clickedIndex).removeAttr('selected');
|
||||
} else {
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$select.find('.filter-option').html($this.text());
|
||||
$select.find('button').focus();
|
||||
|
||||
// Trigger select 'change'
|
||||
$select.prev('select').trigger('change');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.$newElement.on('click', 'li.disabled a, li dt, li .divider', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$select = $(this).parent().parents('.select');
|
||||
$select.find('button').focus();
|
||||
});
|
||||
|
||||
this.$element.on('change', function(e) {
|
||||
_this.render();
|
||||
});
|
||||
},
|
||||
|
||||
val:function(value) {
|
||||
|
||||
if(value!=undefined) {
|
||||
this.$element.val( value );
|
||||
|
||||
this.$element.trigger('change');
|
||||
return this.$element;
|
||||
} else {
|
||||
return this.$element.val();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.selectpicker = function(option, event) {
|
||||
//get the args of the outer function..
|
||||
var args = arguments;
|
||||
var value;
|
||||
var chain = this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('selectpicker'),
|
||||
options = typeof option == 'object' && option;
|
||||
|
||||
if (!data) {
|
||||
$this.data('selectpicker', (data = new Selectpicker(this, options, event)));
|
||||
} else {
|
||||
for(var i in option) {
|
||||
data[i]=option[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof option == 'string') {
|
||||
//Copy the value of option, as once we shift the arguments
|
||||
//it also shifts the value of option.
|
||||
property = option;
|
||||
if(data[property] instanceof Function) {
|
||||
[].shift.apply(args);
|
||||
value = data[property].apply(data, args);
|
||||
} else {
|
||||
value = data[property];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(value!=undefined) {
|
||||
return value;
|
||||
} else {
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.selectpicker.defaults = {
|
||||
style: null,
|
||||
size: 'auto',
|
||||
title: null,
|
||||
selectedTextFormat : 'values',
|
||||
noneSelectedText : 'Nothing selected',
|
||||
width: null,
|
||||
menuStyle: null,
|
||||
toggleSize: null
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
||||
!function($) {
|
||||
var Selectpicker = function(element, options, e) {
|
||||
if (e ) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
this.$element = $(element);
|
||||
this.$newElement = null;
|
||||
this.button = null;
|
||||
|
||||
//Merge defaults, options and data-attributes to make our options
|
||||
this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options);
|
||||
|
||||
//If we have no title yet, check the attribute 'title' (this is missed by jq as its not a data-attribute
|
||||
if(this.options.title==null)
|
||||
this.options.title = this.$element.attr('title');
|
||||
|
||||
//Expose public methods
|
||||
this.val = Selectpicker.prototype.val;
|
||||
this.render = Selectpicker.prototype.render;
|
||||
this.init();
|
||||
};
|
||||
|
||||
Selectpicker.prototype = {
|
||||
|
||||
constructor: Selectpicker,
|
||||
|
||||
init: function (e) {
|
||||
var _this = this;
|
||||
this.$element.hide();
|
||||
this.multiple = this.$element.prop('multiple');
|
||||
|
||||
|
||||
var classList = this.$element.attr('class') !== undefined ? this.$element.attr('class').split(/\s+/) : '';
|
||||
var id = this.$element.attr('id');
|
||||
this.$element.after( this.createView() );
|
||||
this.$newElement = this.$element.next('.select');
|
||||
var select = this.$newElement;
|
||||
var menu = this.$newElement.find('.dropdown-menu');
|
||||
var menuArrow = this.$newElement.find('.dropdown-arrow');
|
||||
var menuA = menu.find('li > a');
|
||||
var liHeight = select.addClass('open').find('.dropdown-menu li > a').outerHeight();
|
||||
select.removeClass('open');
|
||||
var divHeight = menu.find('li .divider').outerHeight(true);
|
||||
var selectOffset_top = this.$newElement.offset().top;
|
||||
var size = 0;
|
||||
var menuHeight = 0;
|
||||
var selectHeight = this.$newElement.outerHeight();
|
||||
this.button = this.$newElement.find('> button');
|
||||
if (id !== undefined) {
|
||||
this.button.attr('id', id);
|
||||
$('label[for="' + id + '"]').click(function(){ select.find('button#'+id).focus(); })
|
||||
}
|
||||
for (var i = 0; i < classList.length; i++) {
|
||||
if(classList[i] != 'selectpicker') {
|
||||
this.$newElement.addClass(classList[i]);
|
||||
}
|
||||
}
|
||||
//If we are multiple, then add the show-tick class by default
|
||||
if(this.multiple) {
|
||||
this.$newElement.addClass('select-multiple');
|
||||
}
|
||||
this.button.addClass(this.options.style);
|
||||
menu.addClass(this.options.menuStyle);
|
||||
menuArrow.addClass(function() {
|
||||
if (_this.options.menuStyle) {
|
||||
return _this.options.menuStyle.replace('dropdown-', 'dropdown-arrow-');
|
||||
}
|
||||
});
|
||||
this.checkDisabled();
|
||||
this.checkTabIndex();
|
||||
this.clickListener();
|
||||
var menuPadding = parseInt(menu.css('padding-top')) + parseInt(menu.css('padding-bottom')) + parseInt(menu.css('border-top-width')) + parseInt(menu.css('border-bottom-width'));
|
||||
if (this.options.size == 'auto') {
|
||||
|
||||
// Creative Tim Changes: We changed the regular function made in bootstrap-select with this function so the getSize() will not be triggered one million times per second while you scroll.
|
||||
|
||||
var getSize = debounce(function() {
|
||||
var selectOffset_top_scroll = selectOffset_top - $(window).scrollTop();
|
||||
var windowHeight = $(window).innerHeight();
|
||||
var menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2;
|
||||
var selectOffset_bot = windowHeight - selectOffset_top_scroll - selectHeight - menuExtras;
|
||||
menuHeight = selectOffset_bot;
|
||||
if (select.hasClass('dropup')) {
|
||||
menuHeight = selectOffset_top_scroll - menuExtras;
|
||||
}
|
||||
//limit menuHeight to 300px to have a smooth transition with cubic bezier on dropdown
|
||||
if(menuHeight >= 300){
|
||||
menuHeight = 300;
|
||||
}
|
||||
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'auto', 'min-height' : liHeight * 3 + 'px'});
|
||||
|
||||
}, 50);
|
||||
|
||||
getSize;
|
||||
$(window).on('scroll', getSize);
|
||||
$(window).on('resize', getSize);
|
||||
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver(getSize).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', getSize);
|
||||
}
|
||||
} else if (this.options.size && this.options.size != 'auto' && menu.find('li').length > this.options.size) {
|
||||
var optIndex = menu.find("li > *").filter(':not(.divider)').slice(0,this.options.size).last().parent().index();
|
||||
var divLength = menu.find("li").slice(0,optIndex + 1).find('.divider').length;
|
||||
menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding;
|
||||
menu.css({'max-height' : menuHeight + 'px', 'overflow-y' : 'scroll'});
|
||||
//console.log('sunt in if');
|
||||
}
|
||||
|
||||
// Listen for updates to the DOM and re render... (Use Mutation Observer when availiable)
|
||||
if (window.MutationObserver) {
|
||||
new MutationObserver($.proxy(this.reloadLi, this)).observe(this.$element.get(0), {
|
||||
childList: true
|
||||
});
|
||||
} else {
|
||||
this.$element.bind('DOMNodeInserted', $.proxy(this.reloadLi, this));
|
||||
}
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
createDropdown: function() {
|
||||
var drop =
|
||||
"<div class='btn-group select'>" +
|
||||
"<button class='btn dropdown-toggle clearfix' data-toggle='dropdown'>" +
|
||||
"<span class='filter-option'></span> " +
|
||||
"<span class='caret'></span>" +
|
||||
"</button>" +
|
||||
"<span class='dropdown-arrow'></span>" +
|
||||
"<ul class='dropdown-menu' role='menu'>" +
|
||||
"</ul>" +
|
||||
"</div>";
|
||||
|
||||
return $(drop);
|
||||
},
|
||||
|
||||
|
||||
createView: function() {
|
||||
var $drop = this.createDropdown();
|
||||
var $li = this.createLi();
|
||||
$drop.find('ul').append($li);
|
||||
return $drop;
|
||||
},
|
||||
|
||||
reloadLi: function() {
|
||||
//Remove all children.
|
||||
this.destroyLi();
|
||||
//Re build
|
||||
$li = this.createLi();
|
||||
this.$newElement.find('ul').append( $li );
|
||||
//render view
|
||||
this.render();
|
||||
},
|
||||
|
||||
destroyLi:function() {
|
||||
this.$newElement.find('li').remove();
|
||||
},
|
||||
|
||||
createLi: function() {
|
||||
|
||||
var _this = this;
|
||||
var _li = [];
|
||||
var _liA = [];
|
||||
var _liHtml = '';
|
||||
|
||||
this.$element.find('option').each(function(){
|
||||
_li.push($(this).text());
|
||||
});
|
||||
|
||||
this.$element.find('option').each(function(index) {
|
||||
//Get the class and text for the option
|
||||
var optionClass = $(this).attr("class") !== undefined ? $(this).attr("class") : '';
|
||||
var text = $(this).text();
|
||||
var subtext = $(this).data('subtext') !== undefined ? '<small class="muted">'+$(this).data('subtext')+'</small>' : '';
|
||||
|
||||
//Append any subtext to the main text.
|
||||
text+=subtext;
|
||||
|
||||
if ($(this).parent().is('optgroup') && $(this).data('divider') != true) {
|
||||
if ($(this).index() == 0) {
|
||||
//Get the opt group label
|
||||
var label = $(this).parent().attr('label');
|
||||
var labelSubtext = $(this).parent().data('subtext') !== undefined ? '<small class="muted">'+$(this).parent().data('subtext')+'</small>' : '';
|
||||
label += labelSubtext;
|
||||
|
||||
if ($(this)[0].index != 0) {
|
||||
_liA.push(
|
||||
'<div class="divider"></div>'+
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass )
|
||||
);
|
||||
} else {
|
||||
_liA.push(
|
||||
'<dt>'+label+'</dt>'+
|
||||
_this.createA(text, "opt " + optionClass ));
|
||||
}
|
||||
} else {
|
||||
_liA.push( _this.createA(text, "opt " + optionClass ) );
|
||||
}
|
||||
} else if ($(this).data('divider') == true) {
|
||||
_liA.push('<div class="divider"></div>');
|
||||
} else if ($(this).data('hidden') == true) {
|
||||
_liA.push('');
|
||||
} else {
|
||||
_liA.push( _this.createA(text, optionClass ) );
|
||||
}
|
||||
});
|
||||
|
||||
if (_li.length > 0) {
|
||||
for (var i = 0; i < _li.length; i++) {
|
||||
var $option = this.$element.find('option').eq(i);
|
||||
_liHtml += "<li rel=" + i + ">" + _liA[i] + "</li>";
|
||||
}
|
||||
}
|
||||
|
||||
//If we dont have a selected item, and we dont have a title, select the first element so something is set in the button
|
||||
if(this.$element.find('option:selected').length==0 && !_this.options.title) {
|
||||
this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
|
||||
return $(_liHtml);
|
||||
},
|
||||
|
||||
createA:function(test, classes) {
|
||||
return '<a tabindex="-1" href="#" class="'+classes+'">' +
|
||||
'<span class="">' + test + '</span>' +
|
||||
'</a>';
|
||||
|
||||
},
|
||||
|
||||
render:function() {
|
||||
var _this = this;
|
||||
|
||||
//Set width of select
|
||||
if (this.options.width == 'auto') {
|
||||
var ulWidth = this.$newElement.find('.dropdown-menu').css('width');
|
||||
this.$newElement.css('width',ulWidth);
|
||||
} else if (this.options.width && this.options.width != 'auto') {
|
||||
this.$newElement.css('width',this.options.width);
|
||||
}
|
||||
|
||||
//Update the LI to match the SELECT
|
||||
this.$element.find('option').each(function(index) {
|
||||
_this.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') );
|
||||
_this.setSelected(index, $(this).is(':selected') );
|
||||
});
|
||||
|
||||
|
||||
|
||||
var selectedItems = this.$element.find('option:selected').map(function(index,value) {
|
||||
if($(this).attr('title')!=undefined) {
|
||||
return $(this).attr('title');
|
||||
} else {
|
||||
return $(this).text();
|
||||
}
|
||||
}).toArray();
|
||||
|
||||
//Convert all the values into a comma delimited string
|
||||
var title = selectedItems.join(", ");
|
||||
|
||||
//If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
|
||||
if(_this.multiple && _this.options.selectedTextFormat.indexOf('count') > -1) {
|
||||
var max = _this.options.selectedTextFormat.split(">");
|
||||
if( (max.length>1 && selectedItems.length > max[1]) || (max.length==1 && selectedItems.length>=2)) {
|
||||
title = selectedItems.length +' of ' + this.$element.find('option').length + ' selected';
|
||||
}
|
||||
}
|
||||
|
||||
//If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
|
||||
if(!title) {
|
||||
title = _this.options.title != undefined ? _this.options.title : _this.options.noneSelectedText;
|
||||
}
|
||||
|
||||
this.$element.next('.select').find('.filter-option').html( title );
|
||||
},
|
||||
|
||||
|
||||
|
||||
setSelected:function(index, selected) {
|
||||
if(selected) {
|
||||
this.$newElement.find('li').eq(index).addClass('selected');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('selected');
|
||||
}
|
||||
},
|
||||
|
||||
setDisabled:function(index, disabled) {
|
||||
if(disabled) {
|
||||
this.$newElement.find('li').eq(index).addClass('disabled');
|
||||
} else {
|
||||
this.$newElement.find('li').eq(index).removeClass('disabled');
|
||||
}
|
||||
},
|
||||
|
||||
checkDisabled: function() {
|
||||
if (this.$element.is(':disabled')) {
|
||||
this.button.addClass('disabled');
|
||||
this.button.click(function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
checkTabIndex: function() {
|
||||
if (this.$element.is('[tabindex]')) {
|
||||
var tabindex = this.$element.attr("tabindex");
|
||||
this.button.attr('tabindex', tabindex);
|
||||
}
|
||||
},
|
||||
|
||||
clickListener: function() {
|
||||
var _this = this;
|
||||
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
|
||||
|
||||
|
||||
this.$newElement.on('click', 'li a', function(e){
|
||||
var clickedIndex = $(this).parent().index(),
|
||||
$this = $(this).parent(),
|
||||
$select = $this.parents('.select');
|
||||
|
||||
|
||||
//Dont close on multi choice menu
|
||||
if(_this.multiple) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
//Dont run if we have been disabled
|
||||
if ($select.prev('select').not(':disabled') && !$(this).parent().hasClass('disabled')){
|
||||
//Deselect all others if not multi select box
|
||||
if (!_this.multiple) {
|
||||
$select.prev('select').find('option').removeAttr('selected');
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
//Else toggle the one we have chosen if we are multi selet.
|
||||
else {
|
||||
var selected = $select.prev('select').find('option').eq(clickedIndex).prop('selected');
|
||||
|
||||
if(selected) {
|
||||
$select.prev('select').find('option').eq(clickedIndex).removeAttr('selected');
|
||||
} else {
|
||||
$select.prev('select').find('option').eq(clickedIndex).prop('selected', true).attr('selected', 'selected');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$select.find('.filter-option').html($this.text());
|
||||
$select.find('button').focus();
|
||||
|
||||
// Trigger select 'change'
|
||||
$select.prev('select').trigger('change');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.$newElement.on('click', 'li.disabled a, li dt, li .divider', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
$select = $(this).parent().parents('.select');
|
||||
$select.find('button').focus();
|
||||
});
|
||||
|
||||
this.$element.on('change', function(e) {
|
||||
_this.render();
|
||||
});
|
||||
},
|
||||
|
||||
val:function(value) {
|
||||
|
||||
if(value!=undefined) {
|
||||
this.$element.val( value );
|
||||
|
||||
this.$element.trigger('change');
|
||||
return this.$element;
|
||||
} else {
|
||||
return this.$element.val();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.selectpicker = function(option, event) {
|
||||
//get the args of the outer function..
|
||||
var args = arguments;
|
||||
var value;
|
||||
var chain = this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('selectpicker'),
|
||||
options = typeof option == 'object' && option;
|
||||
|
||||
if (!data) {
|
||||
$this.data('selectpicker', (data = new Selectpicker(this, options, event)));
|
||||
} else {
|
||||
for(var i in option) {
|
||||
data[i]=option[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof option == 'string') {
|
||||
//Copy the value of option, as once we shift the arguments
|
||||
//it also shifts the value of option.
|
||||
property = option;
|
||||
if(data[property] instanceof Function) {
|
||||
[].shift.apply(args);
|
||||
value = data[property].apply(data, args);
|
||||
} else {
|
||||
value = data[property];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(value!=undefined) {
|
||||
return value;
|
||||
} else {
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.selectpicker.defaults = {
|
||||
style: null,
|
||||
size: 'auto',
|
||||
title: null,
|
||||
selectedTextFormat : 'values',
|
||||
noneSelectedText : 'Nothing selected',
|
||||
width: null,
|
||||
menuStyle: null,
|
||||
toggleSize: null
|
||||
}
|
||||
|
||||
}(window.jQuery);
|
||||
|
14
public/static/js/bootstrap.min.js
vendored
14
public/static/js/bootstrap.min.js
vendored
File diff suppressed because one or more lines are too long
18
public/static/js/chartist.min.js
vendored
18
public/static/js/chartist.min.js
vendored
File diff suppressed because one or more lines are too long
8
public/static/js/jquery.3.2.1.min.js
vendored
8
public/static/js/jquery.3.2.1.min.js
vendored
File diff suppressed because one or more lines are too long
308
public/static/js/light-bootstrap-dashboard.js
vendored
308
public/static/js/light-bootstrap-dashboard.js
vendored
@ -1,154 +1,154 @@
|
||||
/*!
|
||||
|
||||
=========================================================
|
||||
* Light Bootstrap Dashboard - v1.4.0
|
||||
=========================================================
|
||||
|
||||
* Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard
|
||||
* Copyright 2017 Creative Tim (http://www.creative-tim.com)
|
||||
* Licensed under MIT (https://github.com/creativetimofficial/light-bootstrap-dashboard/blob/master/LICENSE.md)
|
||||
|
||||
=========================================================
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
*/
|
||||
|
||||
var searchVisible = 0;
|
||||
var transparent = true;
|
||||
|
||||
var transparentDemo = true;
|
||||
var fixedTop = false;
|
||||
|
||||
var navbar_initialized = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
window_width = $(window).width();
|
||||
|
||||
// check if there is an image set for the sidebar's background
|
||||
lbd.checkSidebarImage();
|
||||
|
||||
// Init navigation toggle for small screens
|
||||
lbd.initRightMenu();
|
||||
|
||||
// Activate the tooltips
|
||||
$('[rel="tooltip"]').tooltip();
|
||||
|
||||
$('.form-control').on("focus", function(){
|
||||
$(this).parent('.input-group').addClass("input-group-focus");
|
||||
}).on("blur", function(){
|
||||
$(this).parent(".input-group").removeClass("input-group-focus");
|
||||
});
|
||||
|
||||
// Fixes sub-nav not working as expected on IOS
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
});
|
||||
|
||||
$(document).on('click', '.navbar-toggle', function(){
|
||||
$toggle = $(this);
|
||||
|
||||
if(lbd.misc.navbar_menu_visible == 1) {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
$('#bodyClick').remove();
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
}, 550);
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
$toggle.addClass('toggled');
|
||||
}, 580);
|
||||
div = '<div id="bodyClick"></div>';
|
||||
$(div).appendTo('body').click(function() {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
$('#bodyClick').remove();
|
||||
}, 550);
|
||||
});
|
||||
|
||||
$('html').addClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 1;
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on('resize', function(){
|
||||
if(navbar_initialized){
|
||||
lbd.initRightMenu();
|
||||
navbar_initialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
lbd = {
|
||||
misc:{
|
||||
navbar_menu_visible: 0
|
||||
},
|
||||
|
||||
checkSidebarImage: function(){
|
||||
$sidebar = $('.sidebar');
|
||||
image_src = $sidebar.data('image');
|
||||
|
||||
if(image_src !== undefined){
|
||||
sidebar_container = '<div class="sidebar-background" style="background-image: url(' + image_src + ') "/>'
|
||||
$sidebar.append(sidebar_container);
|
||||
}
|
||||
},
|
||||
|
||||
initRightMenu: debounce(function(){
|
||||
if(!navbar_initialized){
|
||||
$sidebar_wrapper = $('.sidebar-wrapper');
|
||||
$navbar = $('nav').find('.navbar-collapse').html();
|
||||
|
||||
mobile_menu_content = '';
|
||||
|
||||
nav_content = $navbar;
|
||||
|
||||
nav_content = '<ul class="nav nav-mobile-menu">' + nav_content + '</ul>';
|
||||
|
||||
// navbar_form = $('nav').find('.navbar-form').get(0).outerHTML;
|
||||
|
||||
$sidebar_nav = $sidebar_wrapper.find(' > .nav');
|
||||
|
||||
// insert the navbar form before the sidebar list
|
||||
$nav_content = $(nav_content);
|
||||
// $navbar_form = $(navbar_form);
|
||||
$nav_content.insertBefore($sidebar_nav);
|
||||
// $navbar_form.insertBefore($nav_content);
|
||||
|
||||
$(".sidebar-wrapper .dropdown .dropdown-menu > li > a").click(function(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
});
|
||||
|
||||
mobile_menu_initialized = true;
|
||||
} else {
|
||||
if($(window).width() > 991){
|
||||
// reset all the additions that we made for the sidebar wrapper only if the screen is bigger than 991px
|
||||
// $sidebar_wrapper.find('.navbar-form').remove();
|
||||
$sidebar_wrapper.find('.nav-mobile-menu').remove();
|
||||
|
||||
mobile_menu_initialized = false;
|
||||
}
|
||||
}
|
||||
},200)
|
||||
}
|
||||
|
||||
|
||||
// Returns a function, that, as long as it continues to be invoked, will not
|
||||
// be triggered. The function will be called after it stops being called for
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
}, wait);
|
||||
if (immediate && !timeout) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
/*!
|
||||
|
||||
=========================================================
|
||||
* Light Bootstrap Dashboard - v1.4.0
|
||||
=========================================================
|
||||
|
||||
* Product Page: http://www.creative-tim.com/product/light-bootstrap-dashboard
|
||||
* Copyright 2017 Creative Tim (http://www.creative-tim.com)
|
||||
* Licensed under MIT (https://github.com/creativetimofficial/light-bootstrap-dashboard/blob/master/LICENSE.md)
|
||||
|
||||
=========================================================
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
*/
|
||||
|
||||
var searchVisible = 0;
|
||||
var transparent = true;
|
||||
|
||||
var transparentDemo = true;
|
||||
var fixedTop = false;
|
||||
|
||||
var navbar_initialized = false;
|
||||
|
||||
$(document).ready(function(){
|
||||
window_width = $(window).width();
|
||||
|
||||
// check if there is an image set for the sidebar's background
|
||||
lbd.checkSidebarImage();
|
||||
|
||||
// Init navigation toggle for small screens
|
||||
lbd.initRightMenu();
|
||||
|
||||
// Activate the tooltips
|
||||
$('[rel="tooltip"]').tooltip();
|
||||
|
||||
$('.form-control').on("focus", function(){
|
||||
$(this).parent('.input-group').addClass("input-group-focus");
|
||||
}).on("blur", function(){
|
||||
$(this).parent(".input-group").removeClass("input-group-focus");
|
||||
});
|
||||
|
||||
// Fixes sub-nav not working as expected on IOS
|
||||
$('body').on('touchstart.dropdown', '.dropdown-menu', function (e) { e.stopPropagation(); });
|
||||
});
|
||||
|
||||
$(document).on('click', '.navbar-toggle', function(){
|
||||
$toggle = $(this);
|
||||
|
||||
if(lbd.misc.navbar_menu_visible == 1) {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
$('#bodyClick').remove();
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
}, 550);
|
||||
} else {
|
||||
setTimeout(function(){
|
||||
$toggle.addClass('toggled');
|
||||
}, 580);
|
||||
div = '<div id="bodyClick"></div>';
|
||||
$(div).appendTo('body').click(function() {
|
||||
$('html').removeClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 0;
|
||||
setTimeout(function(){
|
||||
$toggle.removeClass('toggled');
|
||||
$('#bodyClick').remove();
|
||||
}, 550);
|
||||
});
|
||||
|
||||
$('html').addClass('nav-open');
|
||||
lbd.misc.navbar_menu_visible = 1;
|
||||
}
|
||||
});
|
||||
|
||||
$(window).on('resize', function(){
|
||||
if(navbar_initialized){
|
||||
lbd.initRightMenu();
|
||||
navbar_initialized = true;
|
||||
}
|
||||
});
|
||||
|
||||
lbd = {
|
||||
misc:{
|
||||
navbar_menu_visible: 0
|
||||
},
|
||||
|
||||
checkSidebarImage: function(){
|
||||
$sidebar = $('.sidebar');
|
||||
image_src = $sidebar.data('image');
|
||||
|
||||
if(image_src !== undefined){
|
||||
sidebar_container = '<div class="sidebar-background" style="background-image: url(' + image_src + ') "/>'
|
||||
$sidebar.append(sidebar_container);
|
||||
}
|
||||
},
|
||||
|
||||
initRightMenu: debounce(function(){
|
||||
if(!navbar_initialized){
|
||||
$sidebar_wrapper = $('.sidebar-wrapper');
|
||||
$navbar = $('nav').find('.navbar-collapse').html();
|
||||
|
||||
mobile_menu_content = '';
|
||||
|
||||
nav_content = $navbar;
|
||||
|
||||
nav_content = '<ul class="nav nav-mobile-menu">' + nav_content + '</ul>';
|
||||
|
||||
// navbar_form = $('nav').find('.navbar-form').get(0).outerHTML;
|
||||
|
||||
$sidebar_nav = $sidebar_wrapper.find(' > .nav');
|
||||
|
||||
// insert the navbar form before the sidebar list
|
||||
$nav_content = $(nav_content);
|
||||
// $navbar_form = $(navbar_form);
|
||||
$nav_content.insertBefore($sidebar_nav);
|
||||
// $navbar_form.insertBefore($nav_content);
|
||||
|
||||
$(".sidebar-wrapper .dropdown .dropdown-menu > li > a").click(function(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
});
|
||||
|
||||
mobile_menu_initialized = true;
|
||||
} else {
|
||||
if($(window).width() > 991){
|
||||
// reset all the additions that we made for the sidebar wrapper only if the screen is bigger than 991px
|
||||
// $sidebar_wrapper.find('.navbar-form').remove();
|
||||
$sidebar_wrapper.find('.nav-mobile-menu').remove();
|
||||
|
||||
mobile_menu_initialized = false;
|
||||
}
|
||||
}
|
||||
},200)
|
||||
}
|
||||
|
||||
|
||||
// Returns a function, that, as long as it continues to be invoked, will not
|
||||
// be triggered. The function will be called after it stops being called for
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
}, wait);
|
||||
if (immediate && !timeout) func.apply(context, args);
|
||||
};
|
||||
};
|
||||
|
@ -1,56 +1,56 @@
|
||||
{{define "head"}}
|
||||
<title>Tickets | A Discord Support Manager Bot</title>
|
||||
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="Management panel for the Discord Tickets bot">
|
||||
|
||||
<link rel="shortcut icon" href="/assets/img/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet">
|
||||
<link href="/assets/css/style.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
.avatar {
|
||||
background: url("{{.avatar}}?size=32");
|
||||
width: 28px;
|
||||
height: 29px;
|
||||
display: block;
|
||||
background-size: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link href="/assets/css/light-bootstrap-dashboard.css?v=1.4.0" rel="stylesheet"/>
|
||||
<link href="/assets/css/animate.min.css" rel="stylesheet"/>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
|
||||
integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"
|
||||
integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Discord theme -->
|
||||
<link href="/assets/css/discordmock.css" rel="stylesheet"/>
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
||||
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
|
||||
|
||||
<!-- GA -->
|
||||
<script type="80be96f83bbfbba3d4097e23-text/javascript">
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-161945537-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js' type="80be96f83bbfbba3d4097e23-text/javascript"></script>
|
||||
{{define "head"}}
|
||||
<title>Tickets | A Discord Support Manager Bot</title>
|
||||
|
||||
<!-- Meta -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="description" content="Management panel for the Discord Tickets bot">
|
||||
|
||||
<link rel="shortcut icon" href="/assets/img/favicon.ico" type="image/x-icon">
|
||||
<link rel="icon" href="/assets/img/favicon.ico" type="image/x-icon">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700" rel="stylesheet">
|
||||
<link href="/assets/css/style.css" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
.avatar {
|
||||
background: url("{{.avatar}}?size=32");
|
||||
width: 28px;
|
||||
height: 29px;
|
||||
display: block;
|
||||
background-size: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link href="/assets/css/light-bootstrap-dashboard.css?v=1.4.0" rel="stylesheet"/>
|
||||
<link href="/assets/css/animate.min.css" rel="stylesheet"/>
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
|
||||
integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"
|
||||
integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<!-- Discord theme -->
|
||||
<link href="/assets/css/discordmock.css" rel="stylesheet"/>
|
||||
|
||||
<!-- Icons -->
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css"
|
||||
integrity="sha384-oS3vJWv+0UjzBfQzYUhtDYW+Pj2yciDJxpsK1OYPAYjqT085Qq/1cq5FLXAZQ7Ay" crossorigin="anonymous">
|
||||
|
||||
<!-- GA -->
|
||||
<script type="80be96f83bbfbba3d4097e23-text/javascript">
|
||||
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
||||
ga('create', 'UA-161945537-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js' type="80be96f83bbfbba3d4097e23-text/javascript"></script>
|
||||
{{end}}
|
@ -1,23 +1,23 @@
|
||||
{{define "navbar"}}
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/settings">Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/logs/page/1">Logs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/blacklist">Blacklist</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/tickets">Ticket List</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/panels">Reaction Panels</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
{{define "navbar"}}
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/settings">Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/logs/page/1">Logs</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/blacklist">Blacklist</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/tickets">Ticket List</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/manage/{{.guildId}}/panels">Reaction Panels</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
{{end}}
|
@ -1,33 +1,33 @@
|
||||
{{define "sidebar"}}
|
||||
<div class="sidebar" data-color="orange" data-image="/assets/img/sidebar-2.jpg">
|
||||
<div class="sidebar-wrapper">
|
||||
<div class="logo">
|
||||
<a href="https://ticketsbot.net" class="simple-text">
|
||||
TicketsBot
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="nav">
|
||||
<li class="nav-item sidebar-bottom">
|
||||
<a href="/">
|
||||
<i class="fas fa-server"></i>
|
||||
<p>Servers</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item sidebar-bottom" style="bottom: 60px">
|
||||
<a href="/logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<p>Logout</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item sidebar-bottom" style="bottom: 10px">
|
||||
<a href="#">
|
||||
<i class="avatar"></i>
|
||||
<p>{{.name}}</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{define "sidebar"}}
|
||||
<div class="sidebar" data-color="orange" data-image="/assets/img/sidebar-2.jpg">
|
||||
<div class="sidebar-wrapper">
|
||||
<div class="logo">
|
||||
<a href="https://ticketsbot.net" class="simple-text">
|
||||
TicketsBot
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul class="nav">
|
||||
<li class="nav-item sidebar-bottom">
|
||||
<a href="/">
|
||||
<i class="fas fa-server"></i>
|
||||
<p>Servers</p>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item sidebar-bottom" style="bottom: 60px">
|
||||
<a href="/logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<p>Logout</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item sidebar-bottom" style="bottom: 10px">
|
||||
<a href="#">
|
||||
<i class="avatar"></i>
|
||||
<p>{{.name}}</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
@ -1,14 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{{template "sidebar" .}}
|
||||
<div class="main-panel">
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{{template "sidebar" .}}
|
||||
<div class="main-panel">
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,16 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{{template "sidebar" .}}
|
||||
|
||||
<div class="main-panel">
|
||||
{{template "navbar" .}}
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{template "head" .}}
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{{template "sidebar" .}}
|
||||
|
||||
<div class="main-panel">
|
||||
{{template "navbar" .}}
|
||||
{{template "content" .}}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,115 +1,115 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Blacklisted Users</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header collapsed filterCard" id="addBlacklistHeader" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<span class="align-middle" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<i class="fas fa-plus"></i> Add New User
|
||||
</span>
|
||||
</div>
|
||||
<div id="addBlacklist" class="collapse" aria-labelledby="addBlacklistHeader" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" class="form-control" placeholder="Username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 px-1">
|
||||
<label>Discriminator</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<input name="discrim" type="text" class="form-control" placeholder="0000">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>Username#Discrim</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .blacklisted}}
|
||||
<tr>
|
||||
<td>{{.userId}}</td>
|
||||
<td>{{.username}}#{{.discrim}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/blacklist/remove/{{.userId}}?c={{$.csrf}}">Remove</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .userNotFound}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The user you specified couldn't be found
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .isStaff}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You cannot blacklist a staff member
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Blacklisted Users</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header collapsed filterCard" id="addBlacklistHeader" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<span class="align-middle" data-toggle="collapse" data-target="#addBlacklist" aria-expanded="false" aria-controls="addBlacklist">
|
||||
<i class="fas fa-plus"></i> Add New User
|
||||
</span>
|
||||
</div>
|
||||
<div id="addBlacklist" class="collapse" aria-labelledby="addBlacklistHeader" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" class="form-control" placeholder="Username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 px-1">
|
||||
<label>Discriminator</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<input name="discrim" type="text" class="form-control" placeholder="0000">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>Username#Discrim</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .blacklisted}}
|
||||
<tr>
|
||||
<td>{{.userId}}</td>
|
||||
<td>{{.username}}#{{.discrim}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/blacklist/remove/{{.userId}}?c={{$.csrf}}">Remove</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .userNotFound}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The user you specified couldn't be found
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .isStaff}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You cannot blacklist a staff member
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{end}}
|
@ -1,46 +1,46 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Servers</h4>
|
||||
{{if .empty}}
|
||||
<p class="card-category">Select a server to manage below</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{if .empty}}
|
||||
<p class="center-align" style="padding-top: 50px; font-size: 16px">
|
||||
You are not the admin of any guilds that the bot is in. Click below to invite the bot:
|
||||
<br/>
|
||||
<a href="https://invite.ticketsbot.net">Invite</a>
|
||||
</p>
|
||||
{{else}}
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<th>Server Name</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .servers}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/manage/{{.Id}}/settings">
|
||||
{{.Name}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Servers</h4>
|
||||
{{if .empty}}
|
||||
<p class="card-category">Select a server to manage below</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{if .empty}}
|
||||
<p class="center-align" style="padding-top: 50px; font-size: 16px">
|
||||
You are not the admin of any guilds that the bot is in. Click below to invite the bot:
|
||||
<br/>
|
||||
<a href="https://invite.ticketsbot.net">Invite</a>
|
||||
</p>
|
||||
{{else}}
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<th>Server Name</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .servers}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/manage/{{.Id}}/settings">
|
||||
{{.Name}}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
@ -1,100 +1,100 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header collapsed filterCard" id="filterHeader" data-toggle="collapse" data-target="#filterLogs" aria-expanded="false" aria-controls="filterLogs">
|
||||
<span class="align-middle" data-toggle="collapse" data-target="#filterLogs" aria-expanded="false" aria-controls="filterLogs">
|
||||
<i class="fas fa-search"></i> Filter Logs
|
||||
</span>
|
||||
</div>
|
||||
<div id="filterLogs" class="collapse" aria-labelledby="filterHeader" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<form action="/manage/{{.guildId}}/logs/page/1">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Ticket ID</label>
|
||||
<input name="ticketid" type="text" class="form-control" placeholder="Ticket ID">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 px-1">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" class="form-control" placeholder="Username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 px-1">
|
||||
<div class="form-group">
|
||||
<label>User ID</label>
|
||||
<input name="userid" type="text" class="form-control" placeholder="User ID">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Logs</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>Username</th>
|
||||
<th>User ID</th>
|
||||
<th>Log URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .logs}}
|
||||
<tr>
|
||||
<td>{{.ticketid}}</td>
|
||||
<td>{{.username}}</td>
|
||||
<td>{{.userid}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/logs/view/{{.uuid}}">{{.uuid}}</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="pagination justify-content-center">
|
||||
{{if .isPageOne}}
|
||||
<li class="disabled"><a href="#"><i class="fas fa-chevron-left"></i></a></li>
|
||||
{{else}}
|
||||
<li class="waves-effect"><a href="/manage/{{.guildId}}/logs/page/{{.previousPage}}"><i class="fas fa-chevron-left"></i></a></li>
|
||||
{{end}}
|
||||
|
||||
<p class="center-align" style="padding-left: 10px; padding-right: 10px;">Page {{.page}}</p>
|
||||
<li class="waves-effect"><a href="/manage/{{.guildId}}/logs/page/{{.nextPage}}"><i class="fas fa-chevron-right"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header collapsed filterCard" id="filterHeader" data-toggle="collapse" data-target="#filterLogs" aria-expanded="false" aria-controls="filterLogs">
|
||||
<span class="align-middle" data-toggle="collapse" data-target="#filterLogs" aria-expanded="false" aria-controls="filterLogs">
|
||||
<i class="fas fa-search"></i> Filter Logs
|
||||
</span>
|
||||
</div>
|
||||
<div id="filterLogs" class="collapse" aria-labelledby="filterHeader" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<form action="/manage/{{.guildId}}/logs/page/1">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Ticket ID</label>
|
||||
<input name="ticketid" type="text" class="form-control" placeholder="Ticket ID">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 px-1">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" class="form-control" placeholder="Username">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 px-1">
|
||||
<div class="form-group">
|
||||
<label>User ID</label>
|
||||
<input name="userid" type="text" class="form-control" placeholder="User ID">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary mx-auto"><i class="fas fa-paper-plane"></i> Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Logs</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>Username</th>
|
||||
<th>User ID</th>
|
||||
<th>Log URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .logs}}
|
||||
<tr>
|
||||
<td>{{.ticketid}}</td>
|
||||
<td>{{.username}}</td>
|
||||
<td>{{.userid}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/logs/view/{{.uuid}}">{{.uuid}}</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<ul class="pagination justify-content-center">
|
||||
{{if .isPageOne}}
|
||||
<li class="disabled"><a href="#"><i class="fas fa-chevron-left"></i></a></li>
|
||||
{{else}}
|
||||
<li class="waves-effect"><a href="/manage/{{.guildId}}/logs/page/{{.previousPage}}"><i class="fas fa-chevron-left"></i></a></li>
|
||||
{{end}}
|
||||
|
||||
<p class="center-align" style="padding-left: 10px; padding-right: 10px;">Page {{.page}}</p>
|
||||
<li class="waves-effect"><a href="/manage/{{.guildId}}/logs/page/{{.nextPage}}"><i class="fas fa-chevron-right"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
@ -1,235 +1,235 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Reaction Panels</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Your panel quota: <b>{{.panelcount}} / {{if .premium}}∞{{else}}1{{end}}</b></p>
|
||||
|
||||
{{if not .premium}}
|
||||
<p>Note: You can expand your panel quote by purchasing premium</p>
|
||||
{{end}}
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Channel</th>
|
||||
<th>Panel Title</th>
|
||||
<th>Panel Content</th>
|
||||
<th>Ticket Channel Category</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .panels}}
|
||||
<tr>
|
||||
<td>#{{.ChannelName}}</td>
|
||||
<td>{{.Title}}</td>
|
||||
<td>{{.Content}}</td>
|
||||
<td>{{.CategoryName}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/panels/delete/{{.MessageId}}?csrf={{$.csrf}}">Delete</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Create A Panel</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="/manage/{{.guildId}}/panels/create">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Title</label>
|
||||
<input name="title" type="text" class="form-control" placeholder="Open a ticket!">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Content</label>
|
||||
<textarea name="content" type="text" class="form-control"
|
||||
placeholder="By reacting to this ticket, a ticket will be opened for you."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Panel Colour</label>
|
||||
<div class="input-group mb-3">
|
||||
<input name="colour" type="color" class="form-control input-fill" value="#23A31A">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Panel Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="channel">
|
||||
{{range $id, $name := .channels}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Ticket Channel Category</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="categories">
|
||||
{{range $id, $name := .categories}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Reaction Emote</label>
|
||||
<input name="reaction" type="text" class="form-control" placeholder="envelope_with_arrow">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="col-md-2 pr-1 offset-md-5">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if not .validTitle}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel titles must be between 1 and 255 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validContent}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel content must be between 1 and 1024 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validColour}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid panel colour. You must use the hex value of the colour, which you can find <a href="https://www.google.co.uk/search?client=opera&q=html+colour+picker">here</a>.
|
||||
<br />Colour has defaulted to green.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validChannel}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid channel - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validCategory}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid category - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validReaction}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid reaction emote
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .created}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Success</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Your panel has been created. You may need to refresh this page to see it displayed.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .metQuota}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You've hit your panel quota. Premium users can create <b>unlimited panels</b>. Click <a href="https://ticketsbot.net/premium">here</a> to learn more about premium.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Reaction Panels</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>Your panel quota: <b>{{.panelcount}} / {{if .premium}}∞{{else}}1{{end}}</b></p>
|
||||
|
||||
{{if not .premium}}
|
||||
<p>Note: You can expand your panel quote by purchasing premium</p>
|
||||
{{end}}
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Channel</th>
|
||||
<th>Panel Title</th>
|
||||
<th>Panel Content</th>
|
||||
<th>Ticket Channel Category</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .panels}}
|
||||
<tr>
|
||||
<td>#{{.ChannelName}}</td>
|
||||
<td>{{.Title}}</td>
|
||||
<td>{{.Content}}</td>
|
||||
<td>{{.CategoryName}}</td>
|
||||
<td><a href="/manage/{{$.guildId}}/panels/delete/{{.MessageId}}?csrf={{$.csrf}}">Delete</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Create A Panel</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="/manage/{{.guildId}}/panels/create">
|
||||
<div class="row">
|
||||
<div class="col-md-4 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Title</label>
|
||||
<input name="title" type="text" class="form-control" placeholder="Open a ticket!">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Panel Content</label>
|
||||
<textarea name="content" type="text" class="form-control"
|
||||
placeholder="By reacting to this ticket, a ticket will be opened for you."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Panel Colour</label>
|
||||
<div class="input-group mb-3">
|
||||
<input name="colour" type="color" class="form-control input-fill" value="#23A31A">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Panel Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="channel">
|
||||
{{range $id, $name := .channels}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<label class="black">Ticket Channel Category</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="categories">
|
||||
{{range $id, $name := .categories}}
|
||||
<option value="{{$id}}">{{$name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-3 pr-1">
|
||||
<div class="form-group">
|
||||
<label class="black">Reaction Emote</label>
|
||||
<input name="reaction" type="text" class="form-control" placeholder="envelope_with_arrow">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="col-md-2 pr-1 offset-md-5">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if not .validTitle}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel titles must be between 1 and 255 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validContent}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Panel content must be between 1 and 1024 characters long
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validColour}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid panel colour. You must use the hex value of the colour, which you can find <a href="https://www.google.co.uk/search?client=opera&q=html+colour+picker">here</a>.
|
||||
<br />Colour has defaulted to green.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validChannel}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid channel - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validCategory}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid category - please try again
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if not .validReaction}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Invalid reaction emote
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .created}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Success</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
Your panel has been created. You may need to refresh this page to see it displayed.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .metQuota}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
You've hit your panel quota. Premium users can create <b>unlimited panels</b>. Click <a href="https://ticketsbot.net/premium">here</a> to learn more about premium.
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{end}}
|
@ -1,159 +1,159 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Settings</h4>
|
||||
{{if .empty}}
|
||||
<p class="card-category">Select a server to manage below</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-5 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Prefix (Max len. 8)</label>
|
||||
<input name="prefix" type="text" class="form-control" placeholder="t!" value="{{.prefix}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="form-group">
|
||||
<label>Ticket Limit (1-10)</label>
|
||||
<input name="ticketlimit" type="text" class="form-control" placeholder="5" value="{{.ticketLimit}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2 px-1">
|
||||
<div class="form-group">
|
||||
<label>Ping @everyone on ticket open</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="pingeveryone" value="on" {{if .pingEveryone}}checked{{end}} style="width:30px;height:30px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label>Welcome Message (Max len. 1000)</label>
|
||||
<textarea name="welcomeMessage" class="form-control" rows="3" style="resize: none">{{.welcomeMessage}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 pr-1">
|
||||
<label>Archive Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="archivechannel">
|
||||
{{range .channels}}
|
||||
<option {{if eq .ChannelId $.archivechannel }}selected{{end}} value="{{.ChannelId}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="form-group">
|
||||
<label>Channel Category</label>
|
||||
<select class="form-control" name="category">
|
||||
{{range .categories}}
|
||||
<option {{if eq $.activecategory .ChannelId}}selected{{end}} value="{{.ChannelId}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 px-1">
|
||||
<div class="form-group">
|
||||
<label>Allow users to close tickets</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="userscanclose" value="on" {{if .usersCanClose}}checked{{end}} style="width:30px;height:30px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>Ticket Naming Scheme</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-id" value="id" {{if eq .namingScheme "id"}}checked{{end}}>
|
||||
<label class="form-check-label" for="naming-by-id">
|
||||
Ticket ID
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-username" value="username" {{if eq .namingScheme "username"}}checked{{end}}>
|
||||
<label class="form-check-label" for="naming-by-username">
|
||||
Username
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 pr-1">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .invalidPrefix}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The prefix you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .invalidWelcomeMessage}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The welcome message you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .invalidTicketLimit}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The ticket limit you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
$('#pingeveryone').prop('indeterminate', {{.pingEveryone}});
|
||||
</script>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Settings</h4>
|
||||
{{if .empty}}
|
||||
<p class="card-category">Select a server to manage below</p>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post">
|
||||
<div class="row">
|
||||
<div class="col-md-5 pr-1">
|
||||
<div class="form-group">
|
||||
<label>Prefix (Max len. 8)</label>
|
||||
<input name="prefix" type="text" class="form-control" placeholder="t!" value="{{.prefix}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="form-group">
|
||||
<label>Ticket Limit (1-10)</label>
|
||||
<input name="ticketlimit" type="text" class="form-control" placeholder="5" value="{{.ticketLimit}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2 px-1">
|
||||
<div class="form-group">
|
||||
<label>Ping @everyone on ticket open</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="pingeveryone" value="on" {{if .pingEveryone}}checked{{end}} style="width:30px;height:30px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<label>Welcome Message (Max len. 1000)</label>
|
||||
<textarea name="welcomeMessage" class="form-control" rows="3" style="resize: none">{{.welcomeMessage}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 pr-1">
|
||||
<label>Archive Channel</label>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<div class="input-group-text">#</div>
|
||||
</div>
|
||||
<select class="form-control" name="archivechannel">
|
||||
{{range .channels}}
|
||||
<option {{if eq .ChannelId $.archivechannel }}selected{{end}} value="{{.ChannelId}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-5 px-1">
|
||||
<div class="form-group">
|
||||
<label>Channel Category</label>
|
||||
<select class="form-control" name="category">
|
||||
{{range .categories}}
|
||||
<option {{if eq $.activecategory .ChannelId}}selected{{end}} value="{{.ChannelId}}">{{.Name}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-2 px-1">
|
||||
<div class="form-group">
|
||||
<label>Allow users to close tickets</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="userscanclose" value="on" {{if .usersCanClose}}checked{{end}} style="width:30px;height:30px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>Ticket Naming Scheme</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-id" value="id" {{if eq .namingScheme "id"}}checked{{end}}>
|
||||
<label class="form-check-label" for="naming-by-id">
|
||||
Ticket ID
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-username" value="username" {{if eq .namingScheme "username"}}checked{{end}}>
|
||||
<label class="form-check-label" for="naming-by-username">
|
||||
Username
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div class="row">
|
||||
<div class="col-md-1 pr-1">
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><i class="fas fa-paper-plane"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .invalidPrefix}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The prefix you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .invalidWelcomeMessage}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The welcome message you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .invalidTicketLimit}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Warning</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
The ticket limit you specified was invalid
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
$('#pingeveryone').prop('indeterminate', {{.pingEveryone}});
|
||||
</script>
|
||||
</div>
|
||||
{{end}}
|
@ -1,43 +1,43 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Ticket List</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>User</th>
|
||||
<th>Additional Members</th>
|
||||
<th>View</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .tickets}}
|
||||
<tr>
|
||||
<td>{{.ticketId}}</td>
|
||||
<td>{{.username}}#{{.discrim}}</td>
|
||||
<td>{{range .members}}{{.username}}#{{.discrim}}{{.sep}}{{end}}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="/manage/{{$.guildId}}/tickets/view/{{.uuid}}">View</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">Ticket List</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body table-responsive">
|
||||
<table class="table table-hover table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>User</th>
|
||||
<th>Additional Members</th>
|
||||
<th>View</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .tickets}}
|
||||
<tr>
|
||||
<td>{{.ticketId}}</td>
|
||||
<td>{{.username}}#{{.discrim}}</td>
|
||||
<td>{{range .members}}{{.username}}#{{.discrim}}{{.sep}}{{end}}</td>
|
||||
<td><a class="btn btn-primary btn-sm" role="button" href="/manage/{{$.guildId}}/tickets/view/{{.uuid}}">View</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
{{end}}
|
@ -1,122 +1,122 @@
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Close Ticket</h4>
|
||||
<div class="close-container">
|
||||
<form class="form-inline" action="/manage/{{.guildId}}/tickets/view/{{.uuid}}/close" method="post">
|
||||
<input type="text" class="form-control" id="reason" name="reason" placeholder="No reason specified" style="width: 80%">
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div style="padding-left: 10px">
|
||||
<button type="submit" class="btn btn-primary">Close Ticket</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h4 class="card-title">View Ticket</h4>
|
||||
<div class="discord-container">
|
||||
<div class="channel-header">
|
||||
<span class="channel-name">#ticket-{{.ticketId}}</span>
|
||||
</div>
|
||||
<div id="message-container">
|
||||
{{range .messages}}
|
||||
<div class="message">
|
||||
<b>{{.username}}</b>
|
||||
{{.content}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<form action="javascript:sendMessage()">
|
||||
{{if .premium}}
|
||||
<input type="text" class="form-control message-input" id="message" name="message"
|
||||
placeholder="Message #ticket-{{.ticketId}}">
|
||||
{{else}}
|
||||
<input type="text" class="form-control message-input" id="message" name="message"
|
||||
placeholder="Premium users get live messages and can respond through webchat" disabled>
|
||||
{{end}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .isError}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Error</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{.error}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Scroll to bottom
|
||||
let container = document.getElementById("message-container");
|
||||
container.scrollTop = container.scrollHeight;
|
||||
</script>
|
||||
|
||||
{{if .premium}}
|
||||
<script>
|
||||
let ws = new WebSocket("wss://panel.ticketsbot.net/webchat");
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify({
|
||||
"type": "auth",
|
||||
"data": {
|
||||
"guild": "{{.guildId}}",
|
||||
"ticket": "{{.ticketId}}"
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = (evt) => {
|
||||
let data = JSON.parse(evt.data);
|
||||
|
||||
let container = document.getElementById("message-container");
|
||||
|
||||
let element = document.createElement("div");
|
||||
element.className = "message";
|
||||
element.innerHTML = `
|
||||
<b>${data.username}</b>
|
||||
${data.content}
|
||||
`;
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
// Scroll to bottom
|
||||
container.scrollTop = container.scrollHeight;
|
||||
};
|
||||
|
||||
function sendMessage() {
|
||||
let msg = document.getElementById("message").value;
|
||||
document.getElementById("message").value = "";
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
"type": "send",
|
||||
"data": msg
|
||||
}))
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{define "content"}}
|
||||
<div class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">Close Ticket</h4>
|
||||
<div class="close-container">
|
||||
<form class="form-inline" action="/manage/{{.guildId}}/tickets/view/{{.uuid}}/close" method="post">
|
||||
<input type="text" class="form-control" id="reason" name="reason" placeholder="No reason specified" style="width: 80%">
|
||||
<input name="csrf" type="hidden" value="{{.csrf}}">
|
||||
<div style="padding-left: 10px">
|
||||
<button type="submit" class="btn btn-primary">Close Ticket</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h4 class="card-title">View Ticket</h4>
|
||||
<div class="discord-container">
|
||||
<div class="channel-header">
|
||||
<span class="channel-name">#ticket-{{.ticketId}}</span>
|
||||
</div>
|
||||
<div id="message-container">
|
||||
{{range .messages}}
|
||||
<div class="message">
|
||||
<b>{{.username}}</b>
|
||||
{{.content}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="input-container">
|
||||
<form action="javascript:sendMessage()">
|
||||
{{if .premium}}
|
||||
<input type="text" class="form-control message-input" id="message" name="message"
|
||||
placeholder="Message #ticket-{{.ticketId}}">
|
||||
{{else}}
|
||||
<input type="text" class="form-control message-input" id="message" name="message"
|
||||
placeholder="Premium users get live messages and can respond through webchat" disabled>
|
||||
{{end}}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div aria-live="polite" aria-atomic="true" style="position: relative; min-height: 200px;">
|
||||
<div style="position: absolute; right: 10px; min-width: 300px">
|
||||
{{if .isError}}
|
||||
<div class="toast" role="alert" aria-live="assertive" aria-atomic="true" data-autohide="false">
|
||||
<div class="toast-header">
|
||||
<strong class="mr-auto">Error</strong>
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{.error}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('.toast').toast('show');
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Scroll to bottom
|
||||
let container = document.getElementById("message-container");
|
||||
container.scrollTop = container.scrollHeight;
|
||||
</script>
|
||||
|
||||
{{if .premium}}
|
||||
<script>
|
||||
let ws = new WebSocket("wss://panel.ticketsbot.net/webchat");
|
||||
|
||||
ws.onopen = () => {
|
||||
ws.send(JSON.stringify({
|
||||
"type": "auth",
|
||||
"data": {
|
||||
"guild": "{{.guildId}}",
|
||||
"ticket": "{{.ticketId}}"
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
ws.onmessage = (evt) => {
|
||||
let data = JSON.parse(evt.data);
|
||||
|
||||
let container = document.getElementById("message-container");
|
||||
|
||||
let element = document.createElement("div");
|
||||
element.className = "message";
|
||||
element.innerHTML = `
|
||||
<b>${data.username}</b>
|
||||
${data.content}
|
||||
`;
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
// Scroll to bottom
|
||||
container.scrollTop = container.scrollHeight;
|
||||
};
|
||||
|
||||
function sendMessage() {
|
||||
let msg = document.getElementById("message").value;
|
||||
document.getElementById("message").value = "";
|
||||
|
||||
ws.send(JSON.stringify({
|
||||
"type": "send",
|
||||
"data": msg
|
||||
}))
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
@ -1,119 +1,119 @@
|
||||
package discord
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/pasztorpisti/qs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
TokenData struct {
|
||||
ClientId string `qs:"client_id"`
|
||||
ClientSecret string `qs:"client_secret"`
|
||||
GrantType string `qs:"grant_type"`
|
||||
Code string `qs:"code"`
|
||||
RedirectUri string `qs:"redirect_uri"`
|
||||
Scope string `qs:"scope"`
|
||||
}
|
||||
|
||||
RefreshData struct {
|
||||
ClientId string `qs:"client_id"`
|
||||
ClientSecret string `qs:"client_secret"`
|
||||
GrantType string `qs:"grant_type"`
|
||||
RefreshToken string `qs:"refresh_token"`
|
||||
RedirectUri string `qs:"redirect_uri"`
|
||||
Scope string `qs:"scope"`
|
||||
}
|
||||
|
||||
TokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
)
|
||||
|
||||
const TokenEndpoint = "https://discordapp.com/api/oauth2/token"
|
||||
|
||||
func AccessToken(code string) (TokenResponse, error) {
|
||||
data := TokenData{
|
||||
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
|
||||
ClientSecret: config.Conf.Oauth.Secret,
|
||||
GrantType: "authorization_code",
|
||||
Code: code,
|
||||
RedirectUri: config.Conf.Oauth.RedirectUri,
|
||||
Scope: "identify guilds",
|
||||
}
|
||||
|
||||
res, err := tokenPost(data)
|
||||
if err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
var unmarshalled TokenResponse
|
||||
if err = json.Unmarshal(res, &unmarshalled); err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
return unmarshalled, nil
|
||||
}
|
||||
|
||||
func RefreshToken(refreshToken string) (TokenResponse, error) {
|
||||
data := RefreshData{
|
||||
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
|
||||
ClientSecret: config.Conf.Oauth.Secret,
|
||||
GrantType: "refresh_token",
|
||||
RefreshToken: refreshToken,
|
||||
RedirectUri: config.Conf.Oauth.RedirectUri,
|
||||
Scope: "identify guilds",
|
||||
}
|
||||
|
||||
res, err := tokenPost(data)
|
||||
if err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
var unmarshalled TokenResponse
|
||||
if err = json.Unmarshal(res, &unmarshalled); err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
return unmarshalled, nil
|
||||
}
|
||||
|
||||
func tokenPost(body ...interface{}) ([]byte, error) {
|
||||
str, err := qs.Marshal(body[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoded := []byte(str)
|
||||
|
||||
req, err := http.NewRequest("POST", TokenEndpoint, bytes.NewBuffer([]byte(encoded)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", string(ApplicationFormUrlEncoded))
|
||||
|
||||
client := &http.Client{}
|
||||
client.Timeout = 3 * time.Second
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
content, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
package discord
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/TicketsBot/GoPanel/config"
|
||||
"github.com/pasztorpisti/qs"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type (
|
||||
TokenData struct {
|
||||
ClientId string `qs:"client_id"`
|
||||
ClientSecret string `qs:"client_secret"`
|
||||
GrantType string `qs:"grant_type"`
|
||||
Code string `qs:"code"`
|
||||
RedirectUri string `qs:"redirect_uri"`
|
||||
Scope string `qs:"scope"`
|
||||
}
|
||||
|
||||
RefreshData struct {
|
||||
ClientId string `qs:"client_id"`
|
||||
ClientSecret string `qs:"client_secret"`
|
||||
GrantType string `qs:"grant_type"`
|
||||
RefreshToken string `qs:"refresh_token"`
|
||||
RedirectUri string `qs:"redirect_uri"`
|
||||
Scope string `qs:"scope"`
|
||||
}
|
||||
|
||||
TokenResponse struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
TokenType string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
)
|
||||
|
||||
const TokenEndpoint = "https://discordapp.com/api/oauth2/token"
|
||||
|
||||
func AccessToken(code string) (TokenResponse, error) {
|
||||
data := TokenData{
|
||||
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
|
||||
ClientSecret: config.Conf.Oauth.Secret,
|
||||
GrantType: "authorization_code",
|
||||
Code: code,
|
||||
RedirectUri: config.Conf.Oauth.RedirectUri,
|
||||
Scope: "identify guilds",
|
||||
}
|
||||
|
||||
res, err := tokenPost(data)
|
||||
if err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
var unmarshalled TokenResponse
|
||||
if err = json.Unmarshal(res, &unmarshalled); err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
return unmarshalled, nil
|
||||
}
|
||||
|
||||
func RefreshToken(refreshToken string) (TokenResponse, error) {
|
||||
data := RefreshData{
|
||||
ClientId: strconv.Itoa(int(config.Conf.Oauth.Id)),
|
||||
ClientSecret: config.Conf.Oauth.Secret,
|
||||
GrantType: "refresh_token",
|
||||
RefreshToken: refreshToken,
|
||||
RedirectUri: config.Conf.Oauth.RedirectUri,
|
||||
Scope: "identify guilds",
|
||||
}
|
||||
|
||||
res, err := tokenPost(data)
|
||||
if err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
var unmarshalled TokenResponse
|
||||
if err = json.Unmarshal(res, &unmarshalled); err != nil {
|
||||
return TokenResponse{}, err
|
||||
}
|
||||
|
||||
return unmarshalled, nil
|
||||
}
|
||||
|
||||
func tokenPost(body ...interface{}) ([]byte, error) {
|
||||
str, err := qs.Marshal(body[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoded := []byte(str)
|
||||
|
||||
req, err := http.NewRequest("POST", TokenEndpoint, bytes.NewBuffer([]byte(encoded)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", string(ApplicationFormUrlEncoded))
|
||||
|
||||
client := &http.Client{}
|
||||
client.Timeout = 3 * time.Second
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
content, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package channel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
)
|
||||
|
||||
func GetChannelMessages(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/channels/%d/messages", id),
|
||||
}
|
||||
}
|
||||
package channel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
)
|
||||
|
||||
func GetChannelMessages(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/channels/%d/messages", id),
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
package guild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetGuild(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%s", strconv.Itoa(id)),
|
||||
}
|
||||
}
|
||||
package guild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetGuild(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%s", strconv.Itoa(id)),
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package guild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
)
|
||||
|
||||
func GetGuildChannels(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%d/channels", id),
|
||||
}
|
||||
}
|
||||
package guild
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TicketsBot/GoPanel/utils/discord"
|
||||
)
|
||||
|
||||
func GetGuildChannels(id int) discord.Endpoint {
|
||||
return discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BOT,
|
||||
Endpoint: fmt.Sprintf("/guilds/%d/channels", id),
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package user
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUser = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me",
|
||||
}
|
||||
package user
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUser = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me",
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package user
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUserGuilds = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me/guilds",
|
||||
}
|
||||
package user
|
||||
|
||||
import "github.com/TicketsBot/GoPanel/utils/discord"
|
||||
|
||||
var CurrentUserGuilds = discord.Endpoint{
|
||||
RequestType: discord.GET,
|
||||
AuthorizationType: discord.BEARER,
|
||||
Endpoint: "/users/@me/guilds",
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
package objects
|
||||
|
||||
type Activity struct {
|
||||
Name string
|
||||
Type int
|
||||
Url string
|
||||
Timestamps Timestamp
|
||||
ApplicationId string
|
||||
Details string
|
||||
State string
|
||||
Party Party
|
||||
Assets Asset
|
||||
Secrets Secret
|
||||
Instance bool
|
||||
Flags int
|
||||
}
|
||||
package objects
|
||||
|
||||
type Activity struct {
|
||||
Name string
|
||||
Type int
|
||||
Url string
|
||||
Timestamps Timestamp
|
||||
ApplicationId string
|
||||
Details string
|
||||
State string
|
||||
Party Party
|
||||
Assets Asset
|
||||
Secrets Secret
|
||||
Instance bool
|
||||
Flags int
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package objects
|
||||
|
||||
type Asset struct {
|
||||
LargeImage string
|
||||
LargeText string
|
||||
SmallImage string
|
||||
SmallText string
|
||||
}
|
||||
package objects
|
||||
|
||||
type Asset struct {
|
||||
LargeImage string
|
||||
LargeText string
|
||||
SmallImage string
|
||||
SmallText string
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package objects
|
||||
|
||||
type Attachment struct {
|
||||
Id string
|
||||
Filename string
|
||||
Size int
|
||||
url string
|
||||
ProxyUrl string
|
||||
height int
|
||||
Width int
|
||||
}
|
||||
package objects
|
||||
|
||||
type Attachment struct {
|
||||
Id string
|
||||
Filename string
|
||||
Size int
|
||||
url string
|
||||
ProxyUrl string
|
||||
height int
|
||||
Width int
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
package objects
|
||||
|
||||
type Channel struct {
|
||||
Id string
|
||||
Type int
|
||||
GuildId string
|
||||
Position int
|
||||
PermissionsOverwrites []Overwrite
|
||||
Name string
|
||||
Topic string
|
||||
Nsfw bool
|
||||
LastMessageId string
|
||||
Bitrate int
|
||||
userLimit int
|
||||
RateLimitPerUser int
|
||||
Recipients []User
|
||||
Icon string
|
||||
Ownerid string
|
||||
ApplicationId string
|
||||
ParentId string
|
||||
LastPinTimestamp string
|
||||
}
|
||||
package objects
|
||||
|
||||
type Channel struct {
|
||||
Id string
|
||||
Type int
|
||||
GuildId string
|
||||
Position int
|
||||
PermissionsOverwrites []Overwrite
|
||||
Name string
|
||||
Topic string
|
||||
Nsfw bool
|
||||
LastMessageId string
|
||||
Bitrate int
|
||||
userLimit int
|
||||
RateLimitPerUser int
|
||||
Recipients []User
|
||||
Icon string
|
||||
Ownerid string
|
||||
ApplicationId string
|
||||
ParentId string
|
||||
LastPinTimestamp string
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type ClientStatus struct {
|
||||
Desktop string
|
||||
Mobile string
|
||||
Web string
|
||||
}
|
||||
package objects
|
||||
|
||||
type ClientStatus struct {
|
||||
Desktop string
|
||||
Mobile string
|
||||
Web string
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
package objects
|
||||
|
||||
type Embed struct {
|
||||
Title string
|
||||
Type string
|
||||
Description string
|
||||
Url string
|
||||
Timestamp string
|
||||
Color int
|
||||
Footer EmbedField
|
||||
Image EmbedImage
|
||||
Thumbnail EmbedThumbnail
|
||||
Video EmbedVideo
|
||||
Provider EmbedProvider
|
||||
Author EmbedAuthor
|
||||
Fields []EmbedField
|
||||
}
|
||||
package objects
|
||||
|
||||
type Embed struct {
|
||||
Title string
|
||||
Type string
|
||||
Description string
|
||||
Url string
|
||||
Timestamp string
|
||||
Color int
|
||||
Footer EmbedField
|
||||
Image EmbedImage
|
||||
Thumbnail EmbedThumbnail
|
||||
Video EmbedVideo
|
||||
Provider EmbedProvider
|
||||
Author EmbedAuthor
|
||||
Fields []EmbedField
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package objects
|
||||
|
||||
type EmbedAuthor struct {
|
||||
Name string
|
||||
Url string
|
||||
IconUrl string
|
||||
ProxyIconUrl string
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedAuthor struct {
|
||||
Name string
|
||||
Url string
|
||||
IconUrl string
|
||||
ProxyIconUrl string
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type EmbedField struct {
|
||||
Name string
|
||||
Value string
|
||||
Inline bool
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedField struct {
|
||||
Name string
|
||||
Value string
|
||||
Inline bool
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type EmbedFooter struct {
|
||||
Text string
|
||||
IconUrl string
|
||||
ProxyIconUrl string
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedFooter struct {
|
||||
Text string
|
||||
IconUrl string
|
||||
ProxyIconUrl string
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package objects
|
||||
|
||||
type EmbedImage struct {
|
||||
Url string
|
||||
ProxyUrl string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedImage struct {
|
||||
Url string
|
||||
ProxyUrl string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package objects
|
||||
|
||||
type EmbedProvider struct {
|
||||
Name string
|
||||
Url string
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedProvider struct {
|
||||
Name string
|
||||
Url string
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package objects
|
||||
|
||||
type EmbedThumbnail struct {
|
||||
Url string
|
||||
ProxyUrl string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedThumbnail struct {
|
||||
Url string
|
||||
ProxyUrl string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type EmbedVideo struct {
|
||||
Url string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
package objects
|
||||
|
||||
type EmbedVideo struct {
|
||||
Url string
|
||||
Height int
|
||||
Width int
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package objects
|
||||
|
||||
type Emoji struct {
|
||||
Id string
|
||||
Name string
|
||||
Roles []string
|
||||
User User
|
||||
RequireColons bool
|
||||
Managed bool
|
||||
Animated bool
|
||||
}
|
||||
package objects
|
||||
|
||||
type Emoji struct {
|
||||
Id string
|
||||
Name string
|
||||
Roles []string
|
||||
User User
|
||||
RequireColons bool
|
||||
Managed bool
|
||||
Animated bool
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
package objects
|
||||
|
||||
type Message struct {
|
||||
Id string
|
||||
ChannelId string
|
||||
GuildId string
|
||||
Author User
|
||||
Member Member
|
||||
Content string
|
||||
Timestamp string
|
||||
EditedTimestamp string
|
||||
Tts bool
|
||||
MentionEveryone bool
|
||||
Mentions []interface{}
|
||||
MentionsRoles []int64
|
||||
Attachments []Attachment
|
||||
Embeds []Embed
|
||||
Reactions []Reaction
|
||||
Nonce string
|
||||
Pinned bool
|
||||
WebhookId string
|
||||
Type int
|
||||
Activity MessageActivity
|
||||
Application MessageApplication
|
||||
}
|
||||
package objects
|
||||
|
||||
type Message struct {
|
||||
Id string
|
||||
ChannelId string
|
||||
GuildId string
|
||||
Author User
|
||||
Member Member
|
||||
Content string
|
||||
Timestamp string
|
||||
EditedTimestamp string
|
||||
Tts bool
|
||||
MentionEveryone bool
|
||||
Mentions []interface{}
|
||||
MentionsRoles []int64
|
||||
Attachments []Attachment
|
||||
Embeds []Embed
|
||||
Reactions []Reaction
|
||||
Nonce string
|
||||
Pinned bool
|
||||
WebhookId string
|
||||
Type int
|
||||
Activity MessageActivity
|
||||
Application MessageApplication
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package objects
|
||||
|
||||
type MessageActivity struct {
|
||||
Type int
|
||||
PartyId string
|
||||
}
|
||||
package objects
|
||||
|
||||
type MessageActivity struct {
|
||||
Type int
|
||||
PartyId string
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package objects
|
||||
|
||||
type MessageApplication struct {
|
||||
Id string
|
||||
CoverImage string
|
||||
Description string
|
||||
Icon string
|
||||
Name string
|
||||
}
|
||||
package objects
|
||||
|
||||
type MessageApplication struct {
|
||||
Id string
|
||||
CoverImage string
|
||||
Description string
|
||||
Icon string
|
||||
Name string
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package objects
|
||||
|
||||
type Overwrite struct {
|
||||
Id string
|
||||
Type string
|
||||
Allow int
|
||||
Deny int
|
||||
}
|
||||
package objects
|
||||
|
||||
type Overwrite struct {
|
||||
Id string
|
||||
Type string
|
||||
Allow int
|
||||
Deny int
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package objects
|
||||
|
||||
type Party struct {
|
||||
Id string
|
||||
Size []int
|
||||
}
|
||||
package objects
|
||||
|
||||
type Party struct {
|
||||
Id string
|
||||
Size []int
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
package objects
|
||||
|
||||
type Presence struct {
|
||||
User User
|
||||
Roles []string
|
||||
Game Activity
|
||||
GuildId string
|
||||
Status string
|
||||
Activities []Activity
|
||||
ClientStatus ClientStatus
|
||||
}
|
||||
package objects
|
||||
|
||||
type Presence struct {
|
||||
User User
|
||||
Roles []string
|
||||
Game Activity
|
||||
GuildId string
|
||||
Status string
|
||||
Activities []Activity
|
||||
ClientStatus ClientStatus
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type Reaction struct {
|
||||
Count int
|
||||
Me bool
|
||||
Emoji Emoji
|
||||
}
|
||||
package objects
|
||||
|
||||
type Reaction struct {
|
||||
Count int
|
||||
Me bool
|
||||
Emoji Emoji
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package objects
|
||||
|
||||
type Role struct {
|
||||
Id string
|
||||
Name string
|
||||
Color int
|
||||
Hoist bool
|
||||
Position int
|
||||
Permissions int
|
||||
Managed bool
|
||||
Mentionable bool
|
||||
}
|
||||
package objects
|
||||
|
||||
type Role struct {
|
||||
Id string
|
||||
Name string
|
||||
Color int
|
||||
Hoist bool
|
||||
Position int
|
||||
Permissions int
|
||||
Managed bool
|
||||
Mentionable bool
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package objects
|
||||
|
||||
type Secret struct {
|
||||
Join string
|
||||
Spectate string
|
||||
Match string
|
||||
}
|
||||
package objects
|
||||
|
||||
type Secret struct {
|
||||
Join string
|
||||
Spectate string
|
||||
Match string
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package objects
|
||||
|
||||
type Timestamp struct {
|
||||
Start int
|
||||
End int
|
||||
}
|
||||
package objects
|
||||
|
||||
type Timestamp struct {
|
||||
Start int
|
||||
End int
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package objects
|
||||
|
||||
type User struct {
|
||||
Id string
|
||||
Username string
|
||||
Discriminator string
|
||||
Avatar string
|
||||
Verified bool
|
||||
Email string
|
||||
Flags int
|
||||
PremiumType int
|
||||
}
|
||||
package objects
|
||||
|
||||
type User struct {
|
||||
Id string
|
||||
Username string
|
||||
Discriminator string
|
||||
Avatar string
|
||||
Verified bool
|
||||
Email string
|
||||
Flags int
|
||||
PremiumType int
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
package objects
|
||||
|
||||
type VoiceState struct {
|
||||
GuildId string
|
||||
ChannelId string
|
||||
UserId string
|
||||
Member Member
|
||||
SessionId string
|
||||
Deaf bool
|
||||
Mute bool
|
||||
SelfDeaf bool
|
||||
SelfMute bool
|
||||
Suppress bool
|
||||
}
|
||||
package objects
|
||||
|
||||
type VoiceState struct {
|
||||
GuildId string
|
||||
ChannelId string
|
||||
UserId string
|
||||
Member Member
|
||||
SessionId string
|
||||
Deaf bool
|
||||
Mute bool
|
||||
SelfDeaf bool
|
||||
SelfMute bool
|
||||
Suppress bool
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package utils
|
||||
|
||||
import "io/ioutil"
|
||||
|
||||
func ReadFile(path string) (string, error) {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(content), nil
|
||||
}
|
||||
package utils
|
||||
|
||||
import "io/ioutil"
|
||||
|
||||
func ReadFile(path string) (string, error) {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(content), nil
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func IsLoggedIn(store sessions.Session) bool {
|
||||
return store.Get("access_token") != nil &&
|
||||
store.Get("expiry") != nil &&
|
||||
store.Get("refresh_token") != nil &&
|
||||
store.Get("userid") != nil &&
|
||||
store.Get("name") != nil &&
|
||||
store.Get("avatar") != nil &&
|
||||
store.Get("csrf") != nil
|
||||
}
|
||||
|
||||
func GetUserId(store sessions.Session) (int64, error) {
|
||||
return strconv.ParseInt(store.Get("userid").(string), 10, 64)
|
||||
}
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/contrib/sessions"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func IsLoggedIn(store sessions.Session) bool {
|
||||
return store.Get("access_token") != nil &&
|
||||
store.Get("expiry") != nil &&
|
||||
store.Get("refresh_token") != nil &&
|
||||
store.Get("userid") != nil &&
|
||||
store.Get("name") != nil &&
|
||||
store.Get("avatar") != nil &&
|
||||
store.Get("csrf") != nil
|
||||
}
|
||||
|
||||
func GetUserId(store sessions.Session) (int64, error) {
|
||||
return strconv.ParseInt(store.Get("userid").(string), 10, 64)
|
||||
}
|
||||
|
@ -1,42 +1,42 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Contains(s interface{}, elem interface{}) bool {
|
||||
arrV := reflect.ValueOf(s)
|
||||
|
||||
if arrV.Kind() == reflect.Slice {
|
||||
for i := 0; i < arrV.Len(); i++ {
|
||||
|
||||
// XXX - panics if slice element points to an unexported struct field
|
||||
// see https://golang.org/pkg/reflect/#Value.Interface
|
||||
if arrV.Index(i).Interface() == elem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func Insert(slice []objects.Guild, index int, value objects.Guild) []objects.Guild {
|
||||
// Grow the slice by one element.
|
||||
slice = slice[0 : len(slice)+1]
|
||||
// Use copy to move the upper part of the slice out of the way and open a hole.
|
||||
copy(slice[index+1:], slice[index:])
|
||||
// Store the new value.
|
||||
slice[index] = value
|
||||
// Return the result.
|
||||
return slice
|
||||
}
|
||||
|
||||
func Reverse(slice []objects.Message) []objects.Message {
|
||||
for i := len(slice)/2-1; i >= 0; i-- {
|
||||
opp := len(slice)-1-i
|
||||
slice[i], slice[opp] = slice[opp], slice[i]
|
||||
}
|
||||
return slice
|
||||
}
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/TicketsBot/GoPanel/utils/discord/objects"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func Contains(s interface{}, elem interface{}) bool {
|
||||
arrV := reflect.ValueOf(s)
|
||||
|
||||
if arrV.Kind() == reflect.Slice {
|
||||
for i := 0; i < arrV.Len(); i++ {
|
||||
|
||||
// XXX - panics if slice element points to an unexported struct field
|
||||
// see https://golang.org/pkg/reflect/#Value.Interface
|
||||
if arrV.Index(i).Interface() == elem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func Insert(slice []objects.Guild, index int, value objects.Guild) []objects.Guild {
|
||||
// Grow the slice by one element.
|
||||
slice = slice[0 : len(slice)+1]
|
||||
// Use copy to move the upper part of the slice out of the way and open a hole.
|
||||
copy(slice[index+1:], slice[index:])
|
||||
// Store the new value.
|
||||
slice[index] = value
|
||||
// Return the result.
|
||||
return slice
|
||||
}
|
||||
|
||||
func Reverse(slice []objects.Message) []objects.Message {
|
||||
for i := len(slice)/2-1; i >= 0; i-- {
|
||||
opp := len(slice)-1-i
|
||||
slice[i], slice[opp] = slice[opp], slice[i]
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user