ExternalLink
This commit is contained in:
@@ -8,6 +8,7 @@ type Domain struct {
|
||||
SoftwareRepository SoftwareRepositoryInterface
|
||||
ReleaseRepository ReleaseRepositoryInterface
|
||||
FileRepository FileRepositoryInterface
|
||||
ExternalLinkRepository ExternalLinkRepositoryInterface
|
||||
DownloadService DownloadServiceInterface
|
||||
SoftwareUpdaterService SoftwareUpdaterServiceInterface
|
||||
SoftwareService SoftwareServiceInterface
|
||||
@@ -21,6 +22,7 @@ func NewDomain() Domain {
|
||||
software_repository := &SoftwareRepository{db: DB}
|
||||
release_repository := &ReleaseRepository{db: DB}
|
||||
file_repository := NewFileRepository()
|
||||
external_link_repository := &ExternalLinkRepository{db: DB}
|
||||
|
||||
software_service := NewSoftwareService(software_repository, release_repository)
|
||||
|
||||
@@ -28,18 +30,21 @@ func NewDomain() Domain {
|
||||
software_repository,
|
||||
release_repository,
|
||||
file_repository,
|
||||
external_link_repository,
|
||||
)
|
||||
|
||||
ebitengine_updater := NewSoftwareUpdaterEbitengineService(
|
||||
software_repository,
|
||||
release_repository,
|
||||
file_repository,
|
||||
external_link_repository,
|
||||
)
|
||||
|
||||
love_updater := NewSoftwareUpdaterLoveService(
|
||||
software_repository,
|
||||
release_repository,
|
||||
file_repository,
|
||||
external_link_repository,
|
||||
)
|
||||
|
||||
software_updater_service := NewSoftwareUpdaterService(tic80_updater, ebitengine_updater, love_updater)
|
||||
@@ -52,6 +57,7 @@ func NewDomain() Domain {
|
||||
SoftwareRepository: software_repository,
|
||||
ReleaseRepository: release_repository,
|
||||
FileRepository: file_repository,
|
||||
ExternalLinkRepository: external_link_repository,
|
||||
DownloadService: download_service,
|
||||
SoftwareUpdaterService: software_updater_service,
|
||||
SoftwareService: software_service,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package domain
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type ExternalLink struct {
|
||||
gorm.Model
|
||||
SoftwareID uint `gorm:"index" json:"softwareId"`
|
||||
Label string `gorm:"size:128" json:"label"`
|
||||
URL string `gorm:"size:255" json:"url"`
|
||||
}
|
||||
@@ -8,5 +8,6 @@ func MigrateGoDatabase(db *gorm.DB) {
|
||||
db.AutoMigrate(
|
||||
Software{},
|
||||
Release{},
|
||||
ExternalLink{},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@ import "gorm.io/gorm"
|
||||
|
||||
type Software struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"uniqueIndex;size:128" json:"name"`
|
||||
Title string `gorm:"size:255" json:"title"`
|
||||
Author string `gorm:"size:255" json:"author"`
|
||||
Desc string `gorm:"type:text" json:"desc"`
|
||||
Site string `gorm:"size:255" json:"site"`
|
||||
License string `gorm:"size:128" json:"license"`
|
||||
Platform string `gorm:"size:128" json:"platform"`
|
||||
Status string `gorm:"size:20;default:development" json:"status"`
|
||||
Highlighted bool `gorm:"default:false" json:"highlighted"`
|
||||
Releases []Release `json:"-"`
|
||||
Name string `gorm:"uniqueIndex;size:128" json:"name"`
|
||||
Title string `gorm:"size:255" json:"title"`
|
||||
Author string `gorm:"size:255" json:"author"`
|
||||
Desc string `gorm:"type:text" json:"desc"`
|
||||
Story string `gorm:"type:text" json:"story"`
|
||||
License string `gorm:"size:128" json:"license"`
|
||||
Platform string `gorm:"size:128" json:"platform"`
|
||||
Status string `gorm:"size:20;default:development" json:"status"`
|
||||
Highlighted bool `gorm:"default:false" json:"highlighted"`
|
||||
Releases []Release `json:"-"`
|
||||
ExternalLinks []ExternalLink `json:"externalLinks"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package domain
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type ExternalLinkRepositoryInterface interface {
|
||||
UpsertByLabel(softwareID uint, label, url string) error
|
||||
}
|
||||
|
||||
type ExternalLinkRepository struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (r *ExternalLinkRepository) UpsertByLabel(softwareID uint, label, url string) error {
|
||||
var link ExternalLink
|
||||
err := r.db.Where("software_id = ? AND label = ?", softwareID, label).First(&link).Error
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return r.db.Create(&ExternalLink{SoftwareID: softwareID, Label: label, URL: url}).Error
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.db.Model(&link).Update("url", url).Error
|
||||
}
|
||||
@@ -15,7 +15,7 @@ type SoftwareRepository struct {
|
||||
|
||||
func (r *SoftwareRepository) GetHighlighted() (*Software, error) {
|
||||
var software Software
|
||||
if err := r.db.Preload("Releases").Where("highlighted = 1").Order("id DESC").First(&software).Error; err != nil {
|
||||
if err := r.db.Preload("Releases").Preload("ExternalLinks").Where("highlighted = 1").Order("id DESC").First(&software).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func (r *SoftwareRepository) GetHighlighted() (*Software, error) {
|
||||
|
||||
func (r *SoftwareRepository) GetByName(name string) (*Software, error) {
|
||||
var software Software
|
||||
if err := r.db.Preload("Releases").Where("name = ?", name).First(&software).Error; err != nil {
|
||||
if err := r.db.Preload("Releases").Preload("ExternalLinks").Where("name = ?", name).First(&software).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &software, nil
|
||||
@@ -35,7 +35,7 @@ func (r *SoftwareRepository) GetByName(name string) (*Software, error) {
|
||||
|
||||
func (r *SoftwareRepository) List() ([]Software, error) {
|
||||
var softwares []Software
|
||||
if err := r.db.Preload("Releases").Find(&softwares).Error; err != nil {
|
||||
if err := r.db.Preload("Releases").Preload("ExternalLinks").Find(&softwares).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return softwares, nil
|
||||
|
||||
@@ -20,20 +20,23 @@ type SoftwareUpdaterEbitengineServiceInterface interface {
|
||||
}
|
||||
|
||||
type SoftwareUpdaterEbitengineService struct {
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
externalLinkRepository ExternalLinkRepositoryInterface
|
||||
}
|
||||
|
||||
func NewSoftwareUpdaterEbitengineService(
|
||||
software_repository SoftwareRepositoryInterface,
|
||||
release_repository ReleaseRepositoryInterface,
|
||||
file_repository FileRepositoryInterface,
|
||||
external_link_repository ExternalLinkRepositoryInterface,
|
||||
) *SoftwareUpdaterEbitengineService {
|
||||
return &SoftwareUpdaterEbitengineService{
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
externalLinkRepository: external_link_repository,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +75,7 @@ func (s *SoftwareUpdaterEbitengineService) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Ebitengine Updater: Extracted metadata: %+v\n", meta_data)
|
||||
siteURL := meta_data.Site
|
||||
software := s.BuildSoftware(meta_data)
|
||||
|
||||
err = s.softwareRepository.UpdateOrCreate(software)
|
||||
@@ -80,6 +84,12 @@ func (s *SoftwareUpdaterEbitengineService) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if siteURL != "" {
|
||||
if linkErr := s.externalLinkRepository.UpsertByLabel(software.ID, "Source Code", siteURL); linkErr != nil {
|
||||
fmt.Printf("Ebitengine Updater: Error upserting external link: %s\n", linkErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
release := Release{
|
||||
SoftwareID: software.ID,
|
||||
Version: version,
|
||||
@@ -101,7 +111,6 @@ func (s *SoftwareUpdaterEbitengineService) BuildSoftware(metadata SoftwareUpdate
|
||||
Title: metadata.Title,
|
||||
Author: metadata.Author,
|
||||
Desc: metadata.Desc,
|
||||
Site: metadata.Site,
|
||||
License: metadata.License,
|
||||
Platform: "ebitengine",
|
||||
}
|
||||
|
||||
@@ -20,20 +20,23 @@ type SoftwareUpdaterLoveServiceInterface interface {
|
||||
}
|
||||
|
||||
type SoftwareUpdaterLoveService struct {
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
externalLinkRepository ExternalLinkRepositoryInterface
|
||||
}
|
||||
|
||||
func NewSoftwareUpdaterLoveService(
|
||||
software_repository SoftwareRepositoryInterface,
|
||||
release_repository ReleaseRepositoryInterface,
|
||||
file_repository FileRepositoryInterface,
|
||||
external_link_repository ExternalLinkRepositoryInterface,
|
||||
) *SoftwareUpdaterLoveService {
|
||||
return &SoftwareUpdaterLoveService{
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
externalLinkRepository: external_link_repository,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +75,7 @@ func (s *SoftwareUpdaterLoveService) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Love Updater: Extracted metadata: %+v\n", meta_data)
|
||||
siteURL := meta_data.Site
|
||||
software := s.BuildSoftware(meta_data)
|
||||
|
||||
err = s.softwareRepository.UpdateOrCreate(software)
|
||||
@@ -80,6 +84,12 @@ func (s *SoftwareUpdaterLoveService) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if siteURL != "" {
|
||||
if linkErr := s.externalLinkRepository.UpsertByLabel(software.ID, "Source Code", siteURL); linkErr != nil {
|
||||
fmt.Printf("Love Updater: Error upserting external link: %s\n", linkErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
release := Release{
|
||||
SoftwareID: software.ID,
|
||||
Version: version,
|
||||
@@ -101,7 +111,6 @@ func (s *SoftwareUpdaterLoveService) BuildSoftware(metadata SoftwareUpdaterLoveM
|
||||
Title: metadata.Title,
|
||||
Author: metadata.Author,
|
||||
Desc: metadata.Desc,
|
||||
Site: metadata.Site,
|
||||
License: metadata.License,
|
||||
Platform: "love",
|
||||
}
|
||||
|
||||
@@ -12,20 +12,23 @@ type SoftwareUpdaterTIC80ServiceInterface interface {
|
||||
}
|
||||
|
||||
type SoftwareUpdaterTIC80Service struct {
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
softwareRepository SoftwareRepositoryInterface
|
||||
releaseRepository ReleaseRepositoryInterface
|
||||
fileRepository FileRepositoryInterface
|
||||
externalLinkRepository ExternalLinkRepositoryInterface
|
||||
}
|
||||
|
||||
func NewSoftwareUpdaterTIC80Service(
|
||||
software_repository SoftwareRepositoryInterface,
|
||||
release_repository ReleaseRepositoryInterface,
|
||||
file_repository FileRepositoryInterface,
|
||||
external_link_repository ExternalLinkRepositoryInterface,
|
||||
) *SoftwareUpdaterTIC80Service {
|
||||
return &SoftwareUpdaterTIC80Service{
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
softwareRepository: software_repository,
|
||||
releaseRepository: release_repository,
|
||||
fileRepository: file_repository,
|
||||
externalLinkRepository: external_link_repository,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +82,7 @@ func (s *SoftwareUpdaterTIC80Service) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
siteURL := meta_data["site"]
|
||||
software := s.BuildSoftware(meta_data)
|
||||
err = s.softwareRepository.UpdateOrCreate(software)
|
||||
if err != nil {
|
||||
@@ -86,6 +90,12 @@ func (s *SoftwareUpdaterTIC80Service) Update(name, version string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if siteURL != "" {
|
||||
if linkErr := s.externalLinkRepository.UpsertByLabel(software.ID, "Source Code", siteURL); linkErr != nil {
|
||||
fmt.Printf("TIC80 Updater: Error upserting external link: %s\n", linkErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("TIC80 Updater: Creating release for software ID: %d, version: %s\n", software.ID, version)
|
||||
release := Release{
|
||||
SoftwareID: software.ID,
|
||||
@@ -108,7 +118,6 @@ func (s *SoftwareUpdaterTIC80Service) BuildSoftware(metadata map[string]string)
|
||||
Title: metadata["title"],
|
||||
Author: metadata["author"],
|
||||
Desc: metadata["desc"],
|
||||
Site: metadata["site"],
|
||||
License: metadata["license"],
|
||||
Platform: "tic80",
|
||||
}
|
||||
|
||||
@@ -78,23 +78,31 @@ const latestStable = stableReleases[0];
|
||||
<dd class="text-gray-900 font-medium">{software.license}</dd>
|
||||
</div>
|
||||
)}
|
||||
{software.site && (
|
||||
{software.externalLinks && software.externalLinks.map((link: any) => (
|
||||
<div>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">Source Code</dt>
|
||||
<dt class="text-xs font-bold text-gray-400 uppercase tracking-widest mb-1">{link.label}</dt>
|
||||
<dd>
|
||||
<a href={software.site} target="_blank" class="text-purple-600 hover:text-purple-800 font-bold break-all">
|
||||
Visit Repository ↗
|
||||
<a href={link.url} target="_blank" class="text-purple-600 hover:text-purple-800 font-bold break-all">
|
||||
{link.url} ↗
|
||||
</a>
|
||||
</dd>
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Area -->
|
||||
<div class="lg:col-span-2 space-y-8">
|
||||
|
||||
|
||||
<!-- Story -->
|
||||
{software.story && (
|
||||
<div class="bg-white rounded-3xl shadow-xl p-8 border border-gray-100">
|
||||
<h2 class="text-xl font-bold text-gray-900 mb-4">About</h2>
|
||||
<p class="text-gray-700 leading-relaxed whitespace-pre-line">{software.story}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<!-- Latest Release (Prominent Section) -->
|
||||
{latestStable && (
|
||||
<div class="bg-gradient-to-br from-indigo-600 to-purple-700 rounded-3xl shadow-xl p-8 text-white">
|
||||
|
||||
Reference in New Issue
Block a user