feat(playlists): share playlists with revocable read-only links
ci / api / api (push) Successful in 55s
release / release (версия и заметки) (push) Successful in 5s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m21s
ci / ts / ts (packages + web) (push) Successful in 2m19s
release / android (APK в релиз) (push) Successful in 4m45s
release / desktop (Linux и Windows в релиз) (push) Successful in 20m58s
release / prune (старые файлы и прогоны) (push) Successful in 9s
ci / module boundaries / boundaries (push) Successful in 7s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m35s
ci / db / db (push) Successful in 59s
ci / api / api (push) Successful in 55s
release / release (версия и заметки) (push) Successful in 5s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m21s
ci / ts / ts (packages + web) (push) Successful in 2m19s
release / android (APK в релиз) (push) Successful in 4m45s
release / desktop (Linux и Windows в релиз) (push) Successful in 20m58s
release / prune (старые файлы и прогоны) (push) Successful in 9s
ci / module boundaries / boundaries (push) Successful in 7s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m35s
ci / db / db (push) Successful in 59s
This commit is contained in:
1 parent
bfcf6e48b2
commit
0a59059738
23 files changed
+1164
-319
No files matched your search
@@ -742,9 +742,12 @@ type Playlist struct {
|
||||
Id openapi_types.UUID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Revision int `json:"revision"`
|
||||
TrackCount int `json:"track_count"`
|
||||
Tracks []Track `json:"tracks"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// ShareId Действующая ссылка; возвращается только владельцу через /me/playlists
|
||||
ShareId *openapi_types.UUID `json:"share_id"`
|
||||
TrackCount int `json:"track_count"`
|
||||
Tracks []Track `json:"tracks"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// PlaylistInput defines model for PlaylistInput.
|
||||
@@ -759,6 +762,11 @@ type PlaylistList struct {
|
||||
Items []PlaylistSummary `json:"items"`
|
||||
}
|
||||
|
||||
// PlaylistShare defines model for PlaylistShare.
|
||||
type PlaylistShare struct {
|
||||
ShareId openapi_types.UUID `json:"share_id"`
|
||||
}
|
||||
|
||||
// PlaylistSummary defines model for PlaylistSummary.
|
||||
type PlaylistSummary struct {
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
@@ -1901,6 +1909,12 @@ type ServerInterface interface {
|
||||
|
||||
// (PUT /api/v1/me/playlists/{id})
|
||||
UpdatePlaylist(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
|
||||
// Отозвать ссылку (только владелец); повторная публикация создаёт новую ссылку
|
||||
// (DELETE /api/v1/me/playlists/{id}/share)
|
||||
RevokePlaylistShare(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
|
||||
// Создать или вернуть ссылку только для чтения (только владелец)
|
||||
// (POST /api/v1/me/playlists/{id}/share)
|
||||
SharePlaylist(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
|
||||
// Снять реакцию
|
||||
// (DELETE /api/v1/me/reactions/tracks/{id})
|
||||
ClearTrackReaction(w http.ResponseWriter, r *http.Request, id EntityId)
|
||||
@@ -1925,6 +1939,9 @@ type ServerInterface interface {
|
||||
// Сведения о сервере для клиентов
|
||||
// (GET /api/v1/server-info)
|
||||
GetServerInfo(w http.ResponseWriter, r *http.Request)
|
||||
// Прочитать плейлист по действующей ссылке (требуется вход)
|
||||
// (GET /api/v1/shared/playlists/{shareId})
|
||||
GetSharedPlaylist(w http.ResponseWriter, r *http.Request, shareId openapi_types.UUID)
|
||||
// Аудио трека (поддерживает Range)
|
||||
// (GET /api/v1/stream/{id})
|
||||
StreamTrack(w http.ResponseWriter, r *http.Request, id EntityId, params StreamTrackParams)
|
||||
@@ -2362,6 +2379,18 @@ func (_ Unimplemented) UpdatePlaylist(w http.ResponseWriter, r *http.Request, id
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Отозвать ссылку (только владелец); повторная публикация создаёт новую ссылку
|
||||
// (DELETE /api/v1/me/playlists/{id}/share)
|
||||
func (_ Unimplemented) RevokePlaylistShare(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Создать или вернуть ссылку только для чтения (только владелец)
|
||||
// (POST /api/v1/me/playlists/{id}/share)
|
||||
func (_ Unimplemented) SharePlaylist(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Снять реакцию
|
||||
// (DELETE /api/v1/me/reactions/tracks/{id})
|
||||
func (_ Unimplemented) ClearTrackReaction(w http.ResponseWriter, r *http.Request, id EntityId) {
|
||||
@@ -2410,6 +2439,12 @@ func (_ Unimplemented) GetServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Прочитать плейлист по действующей ссылке (требуется вход)
|
||||
// (GET /api/v1/shared/playlists/{shareId})
|
||||
func (_ Unimplemented) GetSharedPlaylist(w http.ResponseWriter, r *http.Request, shareId openapi_types.UUID) {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
// Аудио трека (поддерживает Range)
|
||||
// (GET /api/v1/stream/{id})
|
||||
func (_ Unimplemented) StreamTrack(w http.ResponseWriter, r *http.Request, id EntityId, params StreamTrackParams) {
|
||||
@@ -4388,6 +4423,68 @@ func (siw *ServerInterfaceWrapper) UpdatePlaylist(w http.ResponseWriter, r *http
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// RevokePlaylistShare operation middleware
|
||||
func (siw *ServerInterfaceWrapper) RevokePlaylistShare(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
// ------------- Path parameter "id" -------------
|
||||
var id openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.RevokePlaylistShare(w, r, id)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// SharePlaylist operation middleware
|
||||
func (siw *ServerInterfaceWrapper) SharePlaylist(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
// ------------- Path parameter "id" -------------
|
||||
var id openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.SharePlaylist(w, r, id)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// ClearTrackReaction operation middleware
|
||||
func (siw *ServerInterfaceWrapper) ClearTrackReaction(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -4639,6 +4736,37 @@ func (siw *ServerInterfaceWrapper) GetServerInfo(w http.ResponseWriter, r *http.
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// GetSharedPlaylist operation middleware
|
||||
func (siw *ServerInterfaceWrapper) GetSharedPlaylist(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var err error
|
||||
|
||||
// ------------- Path parameter "shareId" -------------
|
||||
var shareId openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithOptions("simple", "shareId", chi.URLParam(r, "shareId"), &shareId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
|
||||
if err != nil {
|
||||
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "shareId", Err: err})
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
|
||||
|
||||
r = r.WithContext(ctx)
|
||||
|
||||
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
siw.Handler.GetSharedPlaylist(w, r, shareId)
|
||||
}))
|
||||
|
||||
for _, middleware := range siw.HandlerMiddlewares {
|
||||
handler = middleware(handler)
|
||||
}
|
||||
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// StreamTrack operation middleware
|
||||
func (siw *ServerInterfaceWrapper) StreamTrack(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -5448,6 +5576,12 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Put(options.BaseURL+"/api/v1/me/playlists/{id}", wrapper.UpdatePlaylist)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Delete(options.BaseURL+"/api/v1/me/playlists/{id}/share", wrapper.RevokePlaylistShare)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Post(options.BaseURL+"/api/v1/me/playlists/{id}/share", wrapper.SharePlaylist)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Delete(options.BaseURL+"/api/v1/me/reactions/tracks/{id}", wrapper.ClearTrackReaction)
|
||||
})
|
||||
@@ -5472,6 +5606,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/server-info", wrapper.GetServerInfo)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/shared/playlists/{shareId}", wrapper.GetSharedPlaylist)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Get(options.BaseURL+"/api/v1/stream/{id}", wrapper.StreamTrack)
|
||||
})
|
||||
@@ -7400,6 +7537,63 @@ func (response UpdatePlaylistdefaultApplicationProblemPlusJSONResponse) VisitUpd
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type RevokePlaylistShareRequestObject struct {
|
||||
Id openapi_types.UUID `json:"id"`
|
||||
}
|
||||
|
||||
type RevokePlaylistShareResponseObject interface {
|
||||
VisitRevokePlaylistShareResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type RevokePlaylistShare204Response struct {
|
||||
}
|
||||
|
||||
func (response RevokePlaylistShare204Response) VisitRevokePlaylistShareResponse(w http.ResponseWriter) error {
|
||||
w.WriteHeader(204)
|
||||
return nil
|
||||
}
|
||||
|
||||
type RevokePlaylistSharedefaultApplicationProblemPlusJSONResponse struct {
|
||||
Body Problem
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (response RevokePlaylistSharedefaultApplicationProblemPlusJSONResponse) VisitRevokePlaylistShareResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/problem+json")
|
||||
w.WriteHeader(response.StatusCode)
|
||||
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type SharePlaylistRequestObject struct {
|
||||
Id openapi_types.UUID `json:"id"`
|
||||
}
|
||||
|
||||
type SharePlaylistResponseObject interface {
|
||||
VisitSharePlaylistResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type SharePlaylist200JSONResponse PlaylistShare
|
||||
|
||||
func (response SharePlaylist200JSONResponse) VisitSharePlaylistResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type SharePlaylistdefaultApplicationProblemPlusJSONResponse struct {
|
||||
Body Problem
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (response SharePlaylistdefaultApplicationProblemPlusJSONResponse) VisitSharePlaylistResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/problem+json")
|
||||
w.WriteHeader(response.StatusCode)
|
||||
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type ClearTrackReactionRequestObject struct {
|
||||
Id EntityId `json:"id"`
|
||||
}
|
||||
@@ -7627,6 +7821,35 @@ func (response GetServerInfodefaultApplicationProblemPlusJSONResponse) VisitGetS
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type GetSharedPlaylistRequestObject struct {
|
||||
ShareId openapi_types.UUID `json:"shareId"`
|
||||
}
|
||||
|
||||
type GetSharedPlaylistResponseObject interface {
|
||||
VisitGetSharedPlaylistResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type GetSharedPlaylist200JSONResponse Playlist
|
||||
|
||||
func (response GetSharedPlaylist200JSONResponse) VisitGetSharedPlaylistResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type GetSharedPlaylistdefaultApplicationProblemPlusJSONResponse struct {
|
||||
Body Problem
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (response GetSharedPlaylistdefaultApplicationProblemPlusJSONResponse) VisitGetSharedPlaylistResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/problem+json")
|
||||
w.WriteHeader(response.StatusCode)
|
||||
|
||||
return json.NewEncoder(w).Encode(response.Body)
|
||||
}
|
||||
|
||||
type StreamTrackRequestObject struct {
|
||||
Id EntityId `json:"id"`
|
||||
Params StreamTrackParams
|
||||
@@ -8323,6 +8546,12 @@ type StrictServerInterface interface {
|
||||
|
||||
// (PUT /api/v1/me/playlists/{id})
|
||||
UpdatePlaylist(ctx context.Context, request UpdatePlaylistRequestObject) (UpdatePlaylistResponseObject, error)
|
||||
// Отозвать ссылку (только владелец); повторная публикация создаёт новую ссылку
|
||||
// (DELETE /api/v1/me/playlists/{id}/share)
|
||||
RevokePlaylistShare(ctx context.Context, request RevokePlaylistShareRequestObject) (RevokePlaylistShareResponseObject, error)
|
||||
// Создать или вернуть ссылку только для чтения (только владелец)
|
||||
// (POST /api/v1/me/playlists/{id}/share)
|
||||
SharePlaylist(ctx context.Context, request SharePlaylistRequestObject) (SharePlaylistResponseObject, error)
|
||||
// Снять реакцию
|
||||
// (DELETE /api/v1/me/reactions/tracks/{id})
|
||||
ClearTrackReaction(ctx context.Context, request ClearTrackReactionRequestObject) (ClearTrackReactionResponseObject, error)
|
||||
@@ -8347,6 +8576,9 @@ type StrictServerInterface interface {
|
||||
// Сведения о сервере для клиентов
|
||||
// (GET /api/v1/server-info)
|
||||
GetServerInfo(ctx context.Context, request GetServerInfoRequestObject) (GetServerInfoResponseObject, error)
|
||||
// Прочитать плейлист по действующей ссылке (требуется вход)
|
||||
// (GET /api/v1/shared/playlists/{shareId})
|
||||
GetSharedPlaylist(ctx context.Context, request GetSharedPlaylistRequestObject) (GetSharedPlaylistResponseObject, error)
|
||||
// Аудио трека (поддерживает Range)
|
||||
// (GET /api/v1/stream/{id})
|
||||
StreamTrack(ctx context.Context, request StreamTrackRequestObject) (StreamTrackResponseObject, error)
|
||||
@@ -10207,6 +10439,58 @@ func (sh *strictHandler) UpdatePlaylist(w http.ResponseWriter, r *http.Request,
|
||||
}
|
||||
}
|
||||
|
||||
// RevokePlaylistShare operation middleware
|
||||
func (sh *strictHandler) RevokePlaylistShare(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
|
||||
var request RevokePlaylistShareRequestObject
|
||||
|
||||
request.Id = id
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.RevokePlaylistShare(ctx, request.(RevokePlaylistShareRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "RevokePlaylistShare")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(RevokePlaylistShareResponseObject); ok {
|
||||
if err := validResponse.VisitRevokePlaylistShareResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// SharePlaylist operation middleware
|
||||
func (sh *strictHandler) SharePlaylist(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
|
||||
var request SharePlaylistRequestObject
|
||||
|
||||
request.Id = id
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.SharePlaylist(ctx, request.(SharePlaylistRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "SharePlaylist")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(SharePlaylistResponseObject); ok {
|
||||
if err := validResponse.VisitSharePlaylistResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// ClearTrackReaction operation middleware
|
||||
func (sh *strictHandler) ClearTrackReaction(w http.ResponseWriter, r *http.Request, id EntityId) {
|
||||
var request ClearTrackReactionRequestObject
|
||||
@@ -10416,6 +10700,32 @@ func (sh *strictHandler) GetServerInfo(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// GetSharedPlaylist operation middleware
|
||||
func (sh *strictHandler) GetSharedPlaylist(w http.ResponseWriter, r *http.Request, shareId openapi_types.UUID) {
|
||||
var request GetSharedPlaylistRequestObject
|
||||
|
||||
request.ShareId = shareId
|
||||
|
||||
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.GetSharedPlaylist(ctx, request.(GetSharedPlaylistRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "GetSharedPlaylist")
|
||||
}
|
||||
|
||||
response, err := handler(r.Context(), w, r, request)
|
||||
|
||||
if err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
} else if validResponse, ok := response.(GetSharedPlaylistResponseObject); ok {
|
||||
if err := validResponse.VisitGetSharedPlaylistResponse(w); err != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, err)
|
||||
}
|
||||
} else if response != nil {
|
||||
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
|
||||
}
|
||||
}
|
||||
|
||||
// StreamTrack operation middleware
|
||||
func (sh *strictHandler) StreamTrack(w http.ResponseWriter, r *http.Request, id EntityId, params StreamTrackParams) {
|
||||
var request StreamTrackRequestObject
|
||||
@@ -10910,291 +11220,297 @@ func (sh *strictHandler) GetReadyz(w http.ResponseWriter, r *http.Request) {
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"7iBqh3IBAA==",
|
||||
"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",
|
||||
"FISFPIV+v3Hv1r3/PwAA//8ZFRgBKHoBAA==",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package playback
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"pipu/api/internal/api/gen"
|
||||
"pipu/api/internal/platform/apperr"
|
||||
)
|
||||
|
||||
// Repeated sharing preserves the existing URL. After revocation a fresh UUID is allocated.
|
||||
func (st *Store) sharePlaylist(ctx context.Context, owner, id uuid.UUID) (uuid.UUID, error) {
|
||||
var shareID uuid.UUID
|
||||
err := st.pool.QueryRow(ctx, `UPDATE playlists SET share_id=COALESCE(share_id,$3)
|
||||
WHERE id=$1 AND user_id=$2 RETURNING share_id`, id, owner, uuid.New()).Scan(&shareID)
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return uuid.Nil, apperr.NotFound("playlist.not_found", "playlist not found")
|
||||
}
|
||||
return shareID, err
|
||||
}
|
||||
|
||||
func (st *Store) revokePlaylistShare(ctx context.Context, owner, id uuid.UUID) error {
|
||||
result, err := st.pool.Exec(ctx, `UPDATE playlists SET share_id=NULL WHERE id=$1 AND user_id=$2`, id, owner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.RowsAffected() == 0 {
|
||||
return apperr.NotFound("playlist.not_found", "playlist not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) SharePlaylist(ctx context.Context, req gen.SharePlaylistRequestObject) (gen.SharePlaylistResponseObject, error) {
|
||||
user, err := principal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shareID, err := h.store.sharePlaylist(ctx, user.UserID, req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gen.SharePlaylist200JSONResponse{ShareId: shareID}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) RevokePlaylistShare(ctx context.Context, req gen.RevokePlaylistShareRequestObject) (gen.RevokePlaylistShareResponseObject, error) {
|
||||
user, err := principal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = h.store.revokePlaylistShare(ctx, user.UserID, req.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gen.RevokePlaylistShare204Response{}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetSharedPlaylist(ctx context.Context, req gen.GetSharedPlaylistRequestObject) (gen.GetSharedPlaylistResponseObject, error) {
|
||||
user, err := principal(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, err := h.readPlaylist(ctx, user.UserID, req.ShareId, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return gen.GetSharedPlaylist200JSONResponse(p), nil
|
||||
}
|
||||
@@ -67,17 +67,33 @@ func (h *Handler) ListPlaylists(ctx context.Context, _ gen.ListPlaylistsRequestO
|
||||
}
|
||||
|
||||
func (h *Handler) playlist(ctx context.Context, user, id uuid.UUID) (gen.Playlist, error) {
|
||||
return h.readPlaylist(ctx, user, id, false)
|
||||
}
|
||||
|
||||
func (h *Handler) readPlaylist(ctx context.Context, user, id uuid.UUID, shared bool) (gen.Playlist, error) {
|
||||
var out gen.Playlist
|
||||
tx, err := h.store.pool.BeginTx(ctx, pgx.TxOptions{IsoLevel: pgx.RepeatableRead, AccessMode: pgx.ReadOnly})
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer tx.Rollback(ctx)
|
||||
p, err := scanPlaylist(tx.QueryRow(ctx, playlistSelect+` WHERE p.user_id=$1 AND p.id=$2`, user, id))
|
||||
filter := ` WHERE p.user_id=$1 AND p.id=$2`
|
||||
args := []any{user, id}
|
||||
if shared {
|
||||
filter = ` WHERE p.share_id=$1 AND EXISTS (SELECT 1 FROM users u WHERE u.id=p.user_id AND NOT u.is_blocked)`
|
||||
args = []any{id}
|
||||
}
|
||||
p, err := scanPlaylist(tx.QueryRow(ctx, playlistSelect+filter, args...))
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
rows, err := tx.Query(ctx, `SELECT track_id FROM playlist_tracks WHERE playlist_id=$1 ORDER BY position`, id)
|
||||
var shareID *uuid.UUID
|
||||
if !shared {
|
||||
if err = tx.QueryRow(ctx, `SELECT share_id FROM playlists WHERE id=$1`, p.Id).Scan(&shareID); err != nil {
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
rows, err := tx.Query(ctx, `SELECT track_id FROM playlist_tracks WHERE playlist_id=$1 ORDER BY position`, p.Id)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
@@ -99,7 +115,7 @@ func (h *Handler) playlist(ctx context.Context, user, id uuid.UUID) (gen.Playlis
|
||||
if dtos == nil {
|
||||
dtos = []gen.Track{}
|
||||
}
|
||||
out = gen.Playlist{Id: p.Id, Name: p.Name, Description: p.Description, Revision: p.Revision, CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, TrackCount: len(dtos), Tracks: dtos}
|
||||
out = gen.Playlist{ShareId: shareID, Id: p.Id, Name: p.Name, Description: p.Description, Revision: p.Revision, CreatedAt: p.CreatedAt, UpdatedAt: p.UpdatedAt, TrackCount: len(dtos), Tracks: dtos}
|
||||
for _, t := range dtos {
|
||||
out.DurationMs += int64(t.DurationMs)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,40 @@ func TestPlaylistPersistenceAndIsolation(t *testing.T) {
|
||||
require.ErrorIs(t, st.savePlaylist(ctx, other, id, "stolen", "", nil, 1, false), apperr.NotFound("playlist.not_found", ""))
|
||||
_, err = h.DeletePlaylist(auth.WithPrincipal(ctx, auth.Principal{UserID: other}), gen.DeletePlaylistRequestObject{Id: id})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
|
||||
// Sharing grants read access through a separate opaque ID, never through the private owner endpoint.
|
||||
ownerCtx := auth.WithPrincipal(ctx, auth.Principal{UserID: owner})
|
||||
otherCtx := auth.WithPrincipal(ctx, auth.Principal{UserID: other})
|
||||
_, err = h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: id})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
_, err = st.sharePlaylist(ctx, other, id)
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
shareID, err := st.sharePlaylist(ctx, owner, id)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, id, shareID)
|
||||
sameID, err := st.sharePlaylist(ctx, owner, id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, shareID, sameID)
|
||||
response, err := h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: shareID})
|
||||
require.NoError(t, err)
|
||||
shared := gen.Playlist(response.(gen.GetSharedPlaylist200JSONResponse))
|
||||
require.Equal(t, []uuid.UUID{first, second}, []uuid.UUID{shared.Tracks[0].Id, shared.Tracks[1].Id})
|
||||
require.Nil(t, shared.ShareId, "the public DTO does not expose owner sharing controls")
|
||||
got, err = h.playlist(ctx, owner, id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, shareID, *got.ShareId)
|
||||
require.Equal(t, 1, got.Revision, "sharing does not conflict with track editing")
|
||||
_, err = h.GetPlaylist(otherCtx, gen.GetPlaylistRequestObject{Id: id})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
_, err = h.RevokePlaylistShare(otherCtx, gen.RevokePlaylistShareRequestObject{Id: id})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
_, err = h.RevokePlaylistShare(ownerCtx, gen.RevokePlaylistShareRequestObject{Id: id})
|
||||
require.NoError(t, err)
|
||||
_, err = h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: shareID})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
freshID, err := st.sharePlaylist(ctx, owner, id)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, shareID, freshID, "revoked links never revive")
|
||||
require.NoError(t, st.savePlaylist(ctx, owner, id, "Mix", "", []uuid.UUID{second, first}, 1, false))
|
||||
require.ErrorIs(t, st.savePlaylist(ctx, owner, id, "stale", "", nil, 1, false), apperr.Conflict("playlist.conflict", ""))
|
||||
// A missing track rolls back both metadata and membership.
|
||||
@@ -63,6 +97,16 @@ func TestPlaylistPersistenceAndIsolation(t *testing.T) {
|
||||
require.Equal(t, 2, got.Revision)
|
||||
require.Equal(t, "Mix", got.Name)
|
||||
require.Equal(t, second, got.Tracks[0].Id)
|
||||
response, err = h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: freshID})
|
||||
require.NoError(t, err)
|
||||
shared = gen.Playlist(response.(gen.GetSharedPlaylist200JSONResponse))
|
||||
require.Equal(t, second, shared.Tracks[0].Id, "shared pages follow edits to the live playlist")
|
||||
_, err = pool.Exec(ctx, `UPDATE users SET is_blocked=true WHERE id=$1`, owner)
|
||||
require.NoError(t, err)
|
||||
_, err = h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: freshID})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
_, err = pool.Exec(ctx, `UPDATE users SET is_blocked=false WHERE id=$1`, owner)
|
||||
require.NoError(t, err)
|
||||
// Exactly one concurrent write may consume a revision.
|
||||
results := make(chan error, 2)
|
||||
var wg sync.WaitGroup
|
||||
@@ -86,6 +130,8 @@ func TestPlaylistPersistenceAndIsolation(t *testing.T) {
|
||||
require.Equal(t, 1, successes)
|
||||
_, err = h.DeletePlaylist(auth.WithPrincipal(ctx, auth.Principal{UserID: owner}), gen.DeletePlaylistRequestObject{Id: id})
|
||||
require.NoError(t, err)
|
||||
_, err = h.GetSharedPlaylist(otherCtx, gen.GetSharedPlaylistRequestObject{ShareId: freshID})
|
||||
require.ErrorIs(t, err, apperr.NotFound("playlist.not_found", ""))
|
||||
var remaining int
|
||||
require.NoError(t, pool.QueryRow(ctx, `SELECT count(*) FROM playlist_tracks WHERE playlist_id=$1`, id).Scan(&remaining))
|
||||
require.Zero(t, remaining)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package playback
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
"pipu/api/internal/api/gen"
|
||||
"pipu/api/internal/platform/apperr"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -19,3 +22,14 @@ func TestValidatePlaylist(t *testing.T) {
|
||||
require.Error(t, validatePlaylist("Mix", "", []uuid.UUID{uuid.Nil}))
|
||||
require.Error(t, validatePlaylist("Mix", "", make([]uuid.UUID, 2001)))
|
||||
}
|
||||
|
||||
func TestPlaylistSharingRequiresAuthentication(t *testing.T) {
|
||||
h := &Handler{}
|
||||
ctx := context.Background()
|
||||
_, err := h.SharePlaylist(ctx, gen.SharePlaylistRequestObject{Id: uuid.New()})
|
||||
require.ErrorIs(t, err, apperr.Unauthorized("auth.unauthorized", ""))
|
||||
_, err = h.RevokePlaylistShare(ctx, gen.RevokePlaylistShareRequestObject{Id: uuid.New()})
|
||||
require.ErrorIs(t, err, apperr.Unauthorized("auth.unauthorized", ""))
|
||||
_, err = h.GetSharedPlaylist(ctx, gen.GetSharedPlaylistRequestObject{ShareId: uuid.New()})
|
||||
require.ErrorIs(t, err, apperr.Unauthorized("auth.unauthorized", ""))
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
-- +goose Up
|
||||
ALTER TABLE playlists ADD COLUMN share_id uuid;
|
||||
CREATE UNIQUE INDEX playlists_share_id_idx ON playlists (share_id) WHERE share_id IS NOT NULL;
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX playlists_share_id_idx;
|
||||
ALTER TABLE playlists DROP COLUMN share_id;
|
||||
Reference in new issue
Block a user