Commit 034fabaa authored by shajiaiming's avatar shajiaiming

推荐币种管理

parent e1b101c8
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
type Coin struct { type Coin struct {
Model Model
//Id int `gorm:"primary_key"`
Sid string `json:"sid"` Sid string `json:"sid"`
Name string `json:"name"` Name string `json:"name"`
OptionalName string `json:"optional_name"` OptionalName string `json:"optional_name"`
...@@ -131,3 +132,13 @@ func DeleteCoin(id int) error { ...@@ -131,3 +132,13 @@ func DeleteCoin(id int) error {
return nil return nil
} }
func GetCoinsPlatform() ([]*Coin, error) {
var coins []*Coin
err := db.Select("platform").Where("platform <> ?", "").Group("platform").Find(&coins).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return coins, nil
}
package models
import (
"github.com/jinzhu/gorm"
)
type CoinRecommend struct {
Model
Id int `json:"id"`
Recommend int `json:"recommend"`
PlatformId int `json:"platform_id"`
Sort int `json:"sort"`
Type int `json:"type"`
Chain string `json:"chain"`
//Coin Coin `gorm:"foreignkey:Cid"`
Cid int `json:"cid" gorm:"index"` //用于声明这个字段为索引,如果你使用了自动迁移功能则会有所影响,在不使用则无影响
Coin Coin `json:"coin"` //字段,实际是一个嵌套的struct,它利用TagID与Tag模型相互关联,在执行查询的时候,能够达到Article、Tag关联查询的功能
}
func (c CoinRecommend) TableName() string {
return "coin_recommend"
}
func ExistCoinRecommendById(id int) (bool, error) {
var coinRecommend CoinRecommend
err := db.Select("id").Where("id = ?", id).First(&coinRecommend).Error
if err != nil && err != gorm.ErrRecordNotFound {
return false, err
}
if coinRecommend.ID > 0 {
return true, nil
}
return false, nil
}
func GetCoinRecommendTotal(maps interface{}) (int, error) {
var count int
if err := db.Model(&CoinRecommend{}).Where(maps).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
func GetCoinRecommends(pageNum, pageSize int, maps interface{}) ([]*CoinRecommend, error) {
var coinsRecommend []*CoinRecommend
err := db.Preload("Coin").Where(maps).Offset(pageNum).Limit(pageSize).Find(&coinsRecommend).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return coinsRecommend, nil
}
func GetCoinRecommend(id int) (*CoinRecommend, error) {
var coinRecommend CoinRecommend
err := db.Where("id = ?", id).First(&coinRecommend).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
err = db.Model(&coinRecommend).Related(&coinRecommend.Coin, "Cid").Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return &coinRecommend, nil
}
func AddCoinRecommend(data map[string]interface{}) (error) {
coinRecommend := CoinRecommend{
Cid: data["cid"].(int),
Recommend: data["recommend"].(int),
PlatformId: data["platform_id"].(int),
Sort: data["sort"].(int),
Type: data["type"].(int),
Chain: data["chain"].(string),
}
if err := db.Create(&coinRecommend).Error; err != nil {
return err
}
return nil
}
func EditCoinRecommend(id int, data interface{}) error {
if err := db.Model(&CoinRecommend{}).Where("id = ?", id).Updates(data).Error; err != nil {
return err
}
return nil
}
func DeleteCoinRecommend(id int) error {
if err := db.Where("id = ?", id).Delete(CoinRecommend{}).Error; err != nil {
return err
}
return nil
}
package models
import (
"github.com/jinzhu/gorm"
)
type Wallet struct {
Model
Name string `json:"name"`
DownloadUrl string `json:"download_url"`
Introduce string `json:"introduce"`
}
func (w Wallet) TableName() string {
return "coin_platform"
}
func ExistWalletById(id int) (bool, error) {
var wallet Wallet
err := db.Select("id").Where("id = ?", id).First(&wallet).Error
if err != nil && err != gorm.ErrRecordNotFound {
return false, err
}
if wallet.ID > 0 {
return true, nil
}
return false, nil
}
func GetWalletTotal(maps interface{}) (int, error) {
var count int
if err := db.Model(&Wallet{}).Where(maps).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
func GetWallets(pageNum, pageSize int, maps interface{}) ([]*Wallet, error) {
var wallets []*Wallet
err := db.Where(maps).Offset(pageNum).Limit(pageSize).Find(&wallets).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return wallets, nil
}
func GetWallet(id int) (*Wallet, error) {
var wallet Wallet
err := db.Where("id = ?", id).First(&wallet).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
err = db.Model(&wallet).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
return &wallet, nil
}
func AddWallet(data map[string]interface{}) (error) {
wallet := Wallet{
Name: data["name"].(string),
DownloadUrl: data["download_url"].(string),
Introduce: data["introduce"].(string),
}
if err := db.Create(&wallet).Error; err != nil {
return err
}
return nil
}
func EditWallet(id int, data interface{}) error {
if err := db.Model(&Wallet{}).Where("id = ?", id).Updates(data).Error; err != nil {
return err
}
return nil
}
func DeleteWallet(id int) error {
if err := db.Where("id = ?", id).Delete(Wallet{}).Error; err != nil {
return err
}
return nil
}
...@@ -272,3 +272,18 @@ func DeleteCoin(c *gin.Context) { ...@@ -272,3 +272,18 @@ func DeleteCoin(c *gin.Context) {
appG.Response(http.StatusOK, e.SUCCESS, nil) appG.Response(http.StatusOK, e.SUCCESS, nil)
} }
func GetCoinsPlatform(c *gin.Context) {
appG := app.Gin{c}
coinService := coin_service.Coin{}
coins, err := coinService.GetCoinsPlatform()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLES_FAIL, nil)
return
}
data := make(map[string]interface{})
data["lists"] = coins
appG.Response(http.StatusOK, e.SUCCESS, data)
}
package v1
import (
"github.com/gin-gonic/gin"
"github.com/astaxie/beego/validation"
"github.com/Unknwon/com"
"net/http"
"bwallet/pkg/app"
"bwallet/pkg/e"
"bwallet/pkg/util"
"bwallet/pkg/setting"
"bwallet/service/coinRecommend_service"
)
type AddCoinRecommendForm struct {
Cid int `form:"cid" valid:"Required;Min(1)"`
Recommend int `form:"recommend" valid:"Range(1,2)"`
PlatformId int `form:"platform_id" valid:"Required;Min(1)"`
Sort int `form:"sort" valid:"Required;Min(1)"`
Type int `form:"type" valid:"Range(1,2)"`
Chain string `form:"chain" valid:"MaxSize(100)"`
}
type EditCoinRecommendForm struct {
Id int `form:"id" valid:"Required;Min(1)"`
Cid int `form:"cid" valid:"Required;Min(1)"`
Recommend int `form:"recommend" valid:"Range(1,2)"`
PlatformId int `form:"platform_id" valid:"Required;Min(1)"`
Sort int `form:"sort" valid:"Required;Min(1)"`
Type int `form:"type" valid:"Range(1,2)"`
Chain string `form:"chain" valid:"MaxSize(100)"`
}
func (cr *AddCoinRecommendForm) Valid(v *validation.Validation) {
coinRecommendService := coinRecommend_service.CoinRecommend{
Cid: cr.Cid,
PlatformId: cr.PlatformId,
Type: cr.Type,
Chain: cr.Chain,
}
total, _ := coinRecommendService.Count()
if total > 0 {
v.SetError("Cid", "推荐币种已经存在")
}
}
func GetCoinRecommend(c *gin.Context) {
appG := app.Gin{c}
id := com.StrTo(c.Param("id")).MustInt()
valid := validation.Validation{}
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
coinRecommendService := coinRecommend_service.CoinRecommend{Id: id}
exists, err := coinRecommendService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if (!exists) {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
coinRecommend, err := coinRecommendService.Get()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, coinRecommend)
}
func GetCoinsRecommend(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
platform_id := -1
if arg := c.Query("platform_id"); arg != "" {
platform_id = com.StrTo(arg).MustInt()
}
page_size := setting.AppSetting.PageSize
if arg := com.StrTo(c.DefaultQuery("pagesize", "0")).MustInt(); arg != 0 {
page_size = com.StrTo(c.Query("pagesize")).MustInt()
}
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
return
}
coinRecommendService := coinRecommend_service.CoinRecommend{
PlatformId: platform_id,
PageNum: util.GetPage(c),
PageSize: page_size,
}
total, err := coinRecommendService.Count()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_COUNT_ARTICLE_FAIL, nil)
return
}
coinRecommends, err := coinRecommendService.GetAll()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLES_FAIL, nil)
return
}
data := make(map[string]interface{})
data["lists"] = coinRecommends
data["total"] = total
appG.Response(http.StatusOK, e.SUCCESS, data)
}
func AddCoinRecommend(c *gin.Context) {
var (
appG = app.Gin{C: c}
form AddCoinRecommendForm
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
coinRecommendService := coinRecommend_service.CoinRecommend{
Cid: form.Cid,
Recommend: form.Recommend,
PlatformId: form.PlatformId,
Sort: form.Sort,
Type: form.Type,
Chain: form.Chain,
}
if err := coinRecommendService.Add(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func EditCoinRecommend(c *gin.Context) {
var (
appG = app.Gin{C: c}
form = EditCoinRecommendForm{Id: com.StrTo(c.Param("id")).MustInt()}
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
coinRecommendService := coinRecommend_service.CoinRecommend{
Id: form.Id,
Cid: form.Cid,
Recommend: form.Recommend,
PlatformId: form.PlatformId,
Sort: form.Sort,
Type: form.Type,
Chain: form.Chain,
}
exists, err := coinRecommendService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
if err := coinRecommendService.Edit(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func DeleteCoinRecommend(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
id := com.StrTo(c.Param("id")).MustInt()
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
coinRecommendService := coinRecommend_service.CoinRecommend{Id: id}
exists, err := coinRecommendService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
err = coinRecommendService.Delete()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_DELETE_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
package v1
import (
"github.com/gin-gonic/gin"
"github.com/astaxie/beego/validation"
"github.com/Unknwon/com"
"net/http"
"bwallet/pkg/app"
"bwallet/pkg/e"
"bwallet/service/wallet_service"
"bwallet/pkg/util"
"bwallet/pkg/setting"
)
type AddWalletForm struct {
Name string `form:"name" valid:"Required;MinSize(2);MaxSize(50)"`
DownloadUrl string `form:"download_url"`
Introduce string `form:"introduce" valid:"MaxSize(500)"`
}
type EditWalletForm struct {
Id int `form:"id" valid:"Required;Min(1)"`
Name string `form:"name" valid:"Required;MinSize(2);MaxSize(50)"`
DownloadUrl string `form:"download_url"`
Nickname string `form:"nickname" valid:"MaxSize(100)"`
Introduce string `form:"introduce" valid:"MaxSize(500)"`
}
func GetWallet(c *gin.Context) {
appG := app.Gin{c}
id := com.StrTo(c.Param("id")).MustInt()
valid := validation.Validation{}
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
walletService := wallet_service.Wallet{Id: id}
exists, err := walletService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if (!exists) {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
wallet, err := walletService.Get()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, wallet)
}
func GetWallets(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
name := ""
if arg := c.Query("name"); arg != "" {
name = c.Query("name")
}
page_size := setting.AppSetting.PageSize
if arg := com.StrTo(c.DefaultQuery("pagesize", "0")).MustInt(); arg != 0{
page_size = com.StrTo(c.Query("pagesize")).MustInt()
}
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusBadRequest, e.INVALID_PARAMS, nil)
return
}
walletService := wallet_service.Wallet{
Name: name,
PageNum: util.GetPage(c),
PageSize: page_size,
}
total, err := walletService.Count()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_COUNT_ARTICLE_FAIL, nil)
return
}
wallets, err := walletService.GetAll()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_GET_ARTICLES_FAIL, nil)
return
}
data := make(map[string]interface{})
data["lists"] = wallets
data["total"] = total
appG.Response(http.StatusOK, e.SUCCESS, data)
}
func AddWallet(c *gin.Context) {
var (
appG = app.Gin{C: c}
form AddWalletForm
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
walletService := wallet_service.Wallet{
Name: form.Name,
DownloadUrl: form.DownloadUrl,
Introduce: form.Introduce,
}
if err := walletService.Add(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func EditWallet(c *gin.Context) {
var (
appG = app.Gin{C: c}
form = EditWalletForm{Id: com.StrTo(c.Param("id")).MustInt()}
)
httpCode, errCode := app.BindAndValid(c, &form)
if errCode != e.SUCCESS {
appG.Response(httpCode, errCode, nil)
return
}
walletService := wallet_service.Wallet{
Id: form.Id,
Name: form.Name,
DownloadUrl: form.DownloadUrl,
Introduce: form.Introduce,
}
exists, err := walletService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
if err := walletService.Edit(); err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_ADD_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
func DeleteWallet(c *gin.Context) {
appG := app.Gin{C: c}
valid := validation.Validation{}
id := com.StrTo(c.Param("id")).MustInt()
valid.Min(id, 1, "id").Message("ID必须大于0")
if valid.HasErrors() {
app.MarkErrors(valid.Errors)
appG.Response(http.StatusOK, e.INVALID_PARAMS, nil)
return
}
walletService := wallet_service.Wallet{Id: id}
exists, err := walletService.ExistById()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_CHECK_EXIST_ARTICLE_FAIL, nil)
return
}
if !exists {
appG.Response(http.StatusOK, e.ERROR_NOT_EXIST_ARTICLE, nil)
return
}
err = walletService.Delete()
if err != nil {
appG.Response(http.StatusInternalServerError, e.ERROR_DELETE_ARTICLE_FAIL, nil)
return
}
appG.Response(http.StatusOK, e.SUCCESS, nil)
}
...@@ -32,6 +32,19 @@ func InitRouter() *gin.Engine { ...@@ -32,6 +32,19 @@ func InitRouter() *gin.Engine {
apiv1.GET("/coin/:id", v1.GetCoin) apiv1.GET("/coin/:id", v1.GetCoin)
apiv1.PUT("/coin/:id", v1.EditCoin) apiv1.PUT("/coin/:id", v1.EditCoin)
apiv1.DELETE("/coin/:id", v1.DeleteCoin) apiv1.DELETE("/coin/:id", v1.DeleteCoin)
apiv1.GET("/get-platform", v1.GetCoinsPlatform)
apiv1.GET("/wallets", v1.GetWallets)
apiv1.POST("/wallet", v1.AddWallet)
apiv1.GET("/wallet/:id", v1.GetWallet)
apiv1.PUT("/wallet/:id", v1.EditWallet)
apiv1.DELETE("/wallet/:id", v1.DeleteWallet)
apiv1.GET("/coins-recommend", v1.GetCoinsRecommend)
apiv1.POST("/coin-recommend", v1.AddCoinRecommend)
apiv1.GET("/coin-recommend/:id", v1.GetCoinRecommend)
apiv1.PUT("/coin-recommend/:id", v1.EditCoinRecommend)
apiv1.DELETE("/coin-recommend/:id", v1.DeleteCoinRecommend)
} }
return r return r
......
package coinRecommend_service
import (
"bwallet/models"
)
type CoinRecommend struct {
Id int
Cid int
Recommend int
PlatformId int
Sort int
Type int
Chain string
PageNum int
PageSize int
}
func (c *CoinRecommend) Get() (*models.CoinRecommend, error) {
coinRecommend, err := models.GetCoinRecommend(c.Id)
if err != nil {
return nil, err
}
return coinRecommend, nil
}
func (c *CoinRecommend) GetAll() ([]*models.CoinRecommend, error) {
var coinsRecommend []*models.CoinRecommend
coinsRecommend, err := models.GetCoinRecommends(c.PageNum, c.PageSize, c.getMaps())
if err != nil {
return nil, err
}
return coinsRecommend, nil
}
func (c *CoinRecommend) Add() error {
coinRecommend := map[string]interface{}{
"cid": c.Cid,
"recommend": c.Recommend,
"platform_id": c.PlatformId,
"sort": c.Sort,
"type": c.Type,
"chain": c.Chain,
}
if err := models.AddCoinRecommend(coinRecommend); err != nil {
return err
}
return nil
}
func (c *CoinRecommend) Edit() error {
return models.EditCoinRecommend(c.Id, map[string]interface{}{
"cid": c.Cid,
"recommend": c.Recommend,
"platform_id": c.PlatformId,
"sort": c.Sort,
"type": c.Type,
"chain": c.Chain,
})
}
func (c *CoinRecommend) ExistById() (bool, error) {
return models.ExistCoinRecommendById(c.Id)
}
func (c *CoinRecommend) Count() (int, error) {
return models.GetCoinRecommendTotal(c.getMaps())
}
func (c *CoinRecommend) Delete() error {
return models.DeleteCoinRecommend(c.Id)
}
func (c *CoinRecommend) getMaps() (map[string]interface{}) {
maps := make(map[string]interface{})
if c.PlatformId != -1 {
maps["platform_id"] = c.PlatformId
}
if c.Cid != 0 {
maps["cid"] = c.Cid
}
if c.Type != 0 {
maps["type"] = c.Type
}
if c.Chain != "" {
maps["chain"] = c.Chain
}
return maps
}
...@@ -120,6 +120,17 @@ func (c *Coin) Delete() error { ...@@ -120,6 +120,17 @@ func (c *Coin) Delete() error {
return models.DeleteCoin(c.Id) return models.DeleteCoin(c.Id)
} }
func (c *Coin) GetCoinsPlatform() ([]*models.Coin, error) {
var coins []*models.Coin
coins, err := models.GetCoinsPlatform()
if err != nil {
return nil, err
}
return coins, nil
}
func (c *Coin) getMaps() (map[string]interface{}) { func (c *Coin) getMaps() (map[string]interface{}) {
maps := make(map[string]interface{}) maps := make(map[string]interface{})
......
package wallet_service
import (
"bwallet/models"
)
type Wallet struct {
Id int
Name string
DownloadUrl string
Introduce string
PageNum int
PageSize int
}
func (w *Wallet) Get() (*models.Wallet, error) {
wallet, err := models.GetWallet(w.Id)
if err != nil {
return nil, err
}
return wallet, nil
}
func (w *Wallet) GetAll() ([]*models.Wallet, error) {
var wallets []*models.Wallet
wallets, err := models.GetWallets(w.PageNum, w.PageSize, w.getMaps())
if err != nil {
return nil, err
}
return wallets, nil
}
func (w *Wallet) Add() error {
wallet := map[string]interface{}{
"name": w.Name,
"download_url": w.DownloadUrl,
"introduce": w.Introduce,
}
if err := models.AddWallet(wallet); err != nil {
return err
}
return nil
}
func (w *Wallet) Edit() error {
return models.EditWallet(w.Id, map[string]interface{}{
"name": w.Name,
"download_url": w.DownloadUrl,
"introduce": w.Introduce,
})
}
func (w *Wallet) ExistById() (bool, error) {
return models.ExistWalletById(w.Id)
}
func (w *Wallet) Count() (int, error) {
return models.GetWalletTotal(w.getMaps())
}
func (w *Wallet) Delete() error {
return models.DeleteWallet(w.Id)
}
func (c *Wallet) getMaps() (map[string]interface{}) {
maps := make(map[string]interface{})
if c.Name != "" {
maps["name"] = c.Name
}
return maps
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment