fix: PHP versions fallback and auto-migrate on panel start
This commit is contained in:
@@ -13,6 +13,9 @@ FROM alpine:3.20
|
|||||||
RUN apk add --no-cache ca-certificates
|
RUN apk add --no-cache ca-certificates
|
||||||
|
|
||||||
COPY --from=builder /panel /panel
|
COPY --from=builder /panel /panel
|
||||||
|
COPY --from=builder /app/migrations /migrations
|
||||||
|
|
||||||
|
ENV MIGRATIONS_PATH=/migrations
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
|
|||||||
+1
-15
@@ -4,8 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/panelhosting/panel/internal/config"
|
"github.com/panelhosting/panel/internal/config"
|
||||||
"github.com/panelhosting/panel/internal/database"
|
"github.com/panelhosting/panel/internal/database"
|
||||||
@@ -20,7 +18,7 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
migrationsPath, err := resolveMigrationsPath()
|
migrationsPath, err := database.MigrationsPath()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -46,15 +44,3 @@ func main() {
|
|||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
log.Println("database connection ok")
|
log.Println("database connection ok")
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveMigrationsPath() (string, error) {
|
|
||||||
if p := os.Getenv("MIGRATIONS_PATH"); p != "" {
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return filepath.Join(wd, "migrations"), nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ func main() {
|
|||||||
}
|
}
|
||||||
defer pool.Close()
|
defer pool.Close()
|
||||||
|
|
||||||
|
migrationsPath, err := database.MigrationsPath()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := database.RunMigrations(cfg.DatabaseURL, migrationsPath); err != nil {
|
||||||
|
log.Printf("migrate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
srv, err := server.New(pool, cfg)
|
srv, err := server.New(pool, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MigrationsPath() (string, error) {
|
||||||
|
if p := os.Getenv("MIGRATIONS_PATH"); p != "" {
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(wd, "migrations"), nil
|
||||||
|
}
|
||||||
@@ -126,8 +126,7 @@ func dashboardPageHTML(username string) string {
|
|||||||
<tbody id="sites"></tbody></table></div>
|
<tbody id="sites"></tbody></table></div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
async function loadPHP(){const r=await fetch('/api/v1/php-versions');const d=await r.json();const s=document.getElementById('php_version');s.innerHTML='';
|
async function loadPHP(){const fallback=['8.1','8.2','8.3','8.4'];let versions=fallback;try{const r=await fetch('/api/v1/php-versions');const d=await r.json();if(r.ok&&d.versions&&d.versions.length)versions=d.versions;}catch(e){}const s=document.getElementById('php_version');s.innerHTML='';versions.forEach(v=>{const o=document.createElement('option');o.value=v;o.textContent='PHP '+v;s.appendChild(o);});if(versions.length)s.value=versions[versions.length-1];}
|
||||||
(d.versions||[]).forEach(v=>{const o=document.createElement('option');o.value=v;o.textContent='PHP '+v;s.appendChild(o);});}
|
|
||||||
async function loadSites(){const r=await fetch('/api/v1/sites');const d=await r.json();const tb=document.getElementById('sites');tb.innerHTML='';
|
async function loadSites(){const r=await fetch('/api/v1/sites');const d=await r.json();const tb=document.getElementById('sites');tb.innerHTML='';
|
||||||
(d.sites||[]).forEach(site=>{const tr=document.createElement('tr');
|
(d.sites||[]).forEach(site=>{const tr=document.createElement('tr');
|
||||||
tr.innerHTML='<td>'+site.name+'</td><td>'+site.primary_domain+'</td><td>'+(site.php_version||'-')+'</td><td><span class="badge">'+site.status+'</span></td><td><code>'+site.document_root+'</code></td>';
|
tr.innerHTML='<td>'+site.name+'</td><td>'+site.primary_domain+'</td><td>'+(site.php_version||'-')+'</td><td><span class="badge">'+site.status+'</span></td><td><code>'+site.document_root+'</code></td>';
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package phpversions
|
||||||
|
|
||||||
|
var Defaults = []string{"8.1", "8.2", "8.3", "8.4"}
|
||||||
|
|
||||||
|
func Contains(version string) bool {
|
||||||
|
for _, v := range Defaults {
|
||||||
|
if v == version {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
+12
-15
@@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
"github.com/panelhosting/panel/internal/models"
|
"github.com/panelhosting/panel/internal/models"
|
||||||
|
"github.com/panelhosting/panel/internal/phpversions"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SiteRepository struct {
|
type SiteRepository struct {
|
||||||
@@ -121,10 +122,7 @@ func (r *PHPVersionRepository) ListActive(ctx context.Context) ([]string, error)
|
|||||||
SELECT version FROM php_versions WHERE is_active = true ORDER BY sort_order
|
SELECT version FROM php_versions WHERE is_active = true ORDER BY sort_order
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
return phpversions.Defaults, nil
|
||||||
return defaultPHPVersions(), nil
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
@@ -132,25 +130,24 @@ func (r *PHPVersionRepository) ListActive(ctx context.Context) ([]string, error)
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var v string
|
var v string
|
||||||
if err := rows.Scan(&v); err != nil {
|
if err := rows.Scan(&v); err != nil {
|
||||||
return nil, err
|
return phpversions.Defaults, nil
|
||||||
}
|
}
|
||||||
versions = append(versions, v)
|
versions = append(versions, v)
|
||||||
}
|
}
|
||||||
if len(versions) == 0 {
|
if err := rows.Err(); err != nil || len(versions) == 0 {
|
||||||
return defaultPHPVersions(), nil
|
return phpversions.Defaults, nil
|
||||||
}
|
}
|
||||||
return versions, rows.Err()
|
return versions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PHPVersionRepository) IsActive(ctx context.Context, version string) (bool, error) {
|
func (r *PHPVersionRepository) IsActive(ctx context.Context, version string) (bool, error) {
|
||||||
var active bool
|
var active bool
|
||||||
err := r.pool.QueryRow(ctx, `SELECT is_active FROM php_versions WHERE version = $1`, version).Scan(&active)
|
err := r.pool.QueryRow(ctx, `SELECT is_active FROM php_versions WHERE version = $1`, version).Scan(&active)
|
||||||
if errors.Is(err, pgx.ErrNoRows) {
|
if err != nil {
|
||||||
return false, nil
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return phpversions.Contains(version), nil
|
||||||
|
}
|
||||||
|
return phpversions.Contains(version), nil
|
||||||
}
|
}
|
||||||
return active, err
|
return active, nil
|
||||||
}
|
|
||||||
|
|
||||||
func defaultPHPVersions() []string {
|
|
||||||
return []string{"8.1", "8.2", "8.3", "8.4"}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user