Skip to content

set up #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .env.example

This file was deleted.

65 changes: 0 additions & 65 deletions README.md

This file was deleted.

2 changes: 1 addition & 1 deletion app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ function viewVideo(video) {
thumbnailImg.style.display = 'none';
} else {
thumbnailImg.style.display = 'block';
thumbnailImg.src = video.thumbnail_url;
thumbnailImg.src = `${video.thumbnail_url}?v=${Date.now()}`;
}

const videoPlayer = document.getElementById('video-player');
Expand Down
34 changes: 34 additions & 0 deletions assets.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package main

import (
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
)

func (cfg apiConfig) ensureAssetsDir() error {
Expand All @@ -10,3 +15,32 @@ func (cfg apiConfig) ensureAssetsDir() error {
}
return nil
}

func getAssetPath(mediaType string) string {
base := make([]byte, 32)
_, err := rand.Read(base)
if err != nil {
panic("failed to generate video id")
}

videoID := base64.RawURLEncoding.EncodeToString(base)

ext := mediaTypeToExt(mediaType)
return fmt.Sprintf("%s%s", videoID, ext)
}

func (cfg apiConfig) getAssetDiskPath(assetPath string) string {
return filepath.Join(cfg.assetsRoot, assetPath)
}

func (cfg apiConfig) getAssetURL(assetPath string) string {
return fmt.Sprintf("http://localhost:%s/assets/%s", cfg.port, assetPath)
}

func mediaTypeToExt(mediaType string) string {
parts := strings.Split(mediaType, "/")
if len(parts) != 2 {
return ".bin"
}
return "." + parts[1]
}
4 changes: 2 additions & 2 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package main

import "net/http"

func cacheMiddleware(next http.Handler) http.Handler {
func noCacheMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "max-age=3600")
w.Header().Set("Cache-Control", "no-store")
next.ServeHTTP(w, r)
})
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/bootdotdev/learn-file-storage-s3-golang-starter
module github.com/imhasandl/learn-file-storage-s3-golang-starter

go 1.23.0

Expand Down
32 changes: 0 additions & 32 deletions handler_get_thumbnail.go

This file was deleted.

4 changes: 2 additions & 2 deletions handler_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"net/http"
"time"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/database"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/database"
)

func (cfg *apiConfig) handlerLogin(w http.ResponseWriter, r *http.Request) {
Expand Down
2 changes: 1 addition & 1 deletion handler_refresh.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"net/http"
"time"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/auth"
)

func (cfg *apiConfig) handlerRefresh(w http.ResponseWriter, r *http.Request) {
Expand Down
59 changes: 54 additions & 5 deletions handler_upload_thumbnail.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package main

import (
"fmt"
"io"
"mime"
"net/http"
"os"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/google/uuid"
)

Expand All @@ -28,10 +30,57 @@ func (cfg *apiConfig) handlerUploadThumbnail(w http.ResponseWriter, r *http.Requ
return
}

const maxMemory = 10 << 20 // 10 MB
r.ParseMultipartForm(maxMemory)

fmt.Println("uploading thumbnail for video", videoID, "by user", userID)
file, header, err := r.FormFile("thumbnail")
if err != nil {
respondWithError(w, http.StatusBadRequest, "Unable to parse form file", err)
return
}
defer file.Close()

// TODO: implement the upload here
mediaType, _, err := mime.ParseMediaType(header.Header.Get("Content-Type"))
if err != nil {
respondWithError(w, http.StatusBadRequest, "Invalid Content-Type", err)
return
}
if mediaType != "image/jpeg" && mediaType != "image/png" {
respondWithError(w, http.StatusBadRequest, "Invalid file type", nil)
return
}

assetPath := getAssetPath(mediaType)
assetDiskPath := cfg.getAssetDiskPath(assetPath)

dst, err := os.Create(assetDiskPath)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Unable to create file on server", err)
return
}
defer dst.Close()
if _, err = io.Copy(dst, file); err != nil {
respondWithError(w, http.StatusInternalServerError, "Error saving file", err)
return
}

video, err := cfg.db.GetVideo(videoID)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't find video", err)
return
}
if video.UserID != userID {
respondWithError(w, http.StatusUnauthorized, "Not authorized to update this video", nil)
return
}

url := cfg.getAssetURL(assetPath)
video.ThumbnailURL = &url
err = cfg.db.UpdateVideo(video)
if err != nil {
respondWithError(w, http.StatusInternalServerError, "Couldn't update video", err)
return
}

respondWithJSON(w, http.StatusOK, struct{}{})
respondWithJSON(w, http.StatusOK, video)
}
4 changes: 2 additions & 2 deletions handler_users.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"encoding/json"
"net/http"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/database"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/database"
)

func (cfg *apiConfig) handlerUsersCreate(w http.ResponseWriter, r *http.Request) {
Expand Down
4 changes: 2 additions & 2 deletions handler_video_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"encoding/json"
"net/http"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/database"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/auth"
"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/database"
"github.com/google/uuid"
)

Expand Down
2 changes: 1 addition & 1 deletion internal/database/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type User struct {

type CreateUserParams struct {
Email string `json:"email"`
Password string `json:"password"`
Password string `json:"-"`
}

func (c Client) GetUsers() ([]User, error) {
Expand Down
16 changes: 3 additions & 13 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import (
"net/http"
"os"

"github.com/bootdotdev/learn-file-storage-s3-golang-starter/internal/database"
"github.com/google/uuid"

"github.com/imhasandl/learn-file-storage-s3-golang-starter/internal/database"
"github.com/joho/godotenv"
_ "github.com/lib/pq"
)
Expand All @@ -24,13 +22,6 @@ type apiConfig struct {
port string
}

type thumbnail struct {
data []byte
mediaType string
}

var videoThumbnails = map[uuid.UUID]thumbnail{}

func main() {
godotenv.Load(".env")

Expand Down Expand Up @@ -106,11 +97,11 @@ func main() {
mux.Handle("/app/", appHandler)

assetsHandler := http.StripPrefix("/assets", http.FileServer(http.Dir(assetsRoot)))
mux.Handle("/assets/", cacheMiddleware(assetsHandler))
mux.Handle("/assets/", noCacheMiddleware(assetsHandler))

mux.HandleFunc("POST /api/login", cfg.handlerLogin)
mux.HandleFunc("POST /api/refresh", cfg.handlerRefresh)
mux.HandleFunc("POST /api/revoke", cfg.handlerRevoke)
mux.HandleFunc("POScT /api/revoke", cfg.handlerRevoke)

mux.HandleFunc("POST /api/users", cfg.handlerUsersCreate)

Expand All @@ -119,7 +110,6 @@ func main() {
mux.HandleFunc("POST /api/video_upload/{videoID}", cfg.handlerUploadVideo)
mux.HandleFunc("GET /api/videos", cfg.handlerVideosRetrieve)
mux.HandleFunc("GET /api/videos/{videoID}", cfg.handlerVideoGet)
mux.HandleFunc("GET /api/thumbnails/{videoID}", cfg.handlerThumbnailGet)
mux.HandleFunc("DELETE /api/videos/{videoID}", cfg.handlerVideoMetaDelete)

mux.HandleFunc("POST /admin/reset", cfg.handlerReset)
Expand Down