package shorturlimpl import ( "context" "fmt" "path" "strings" "time" "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/apimachinery/identity" "github.com/grafana/grafana/pkg/infra/db" "github.com/grafana/grafana/pkg/services/shorturls" "github.com/grafana/grafana/pkg/util" ) var getTime = time.Now type ShortURLService struct { SQLStore store } func ProvideService(db db.DB) *ShortURLService { return &ShortURLService{ SQLStore: &sqlStore{ db: db, }, } } func (s ShortURLService) GetShortURLByUID(ctx context.Context, user identity.Requester, uid string) (*shorturls.ShortUrl, error) { return s.SQLStore.Get(ctx, user, uid) } func (s ShortURLService) UpdateLastSeenAt(ctx context.Context, shortURL *shorturls.ShortUrl) error { return s.SQLStore.Update(ctx, shortURL) } func (s ShortURLService) List(ctx context.Context, orgID int64) ([]*shorturls.ShortUrl, error) { return s.SQLStore.List(ctx, orgID) } func (s ShortURLService) CreateShortURL(ctx context.Context, user identity.Requester, cmd *dtos.CreateShortURLCmd) (*shorturls.ShortUrl, error) { relPath := strings.TrimSpace(cmd.Path) if path.IsAbs(relPath) { return nil, shorturls.ErrShortURLAbsolutePath.Errorf("expected relative path: %s", relPath) } if strings.Contains(relPath, "../") { return nil, shorturls.ErrShortURLInvalidPath.Errorf("path cannot contain '../': %s", relPath) } uid := cmd.UID if uid == "" { uid = util.GenerateShortUID() } else { // Ensure the UID is valid if !util.IsValidShortUID(uid) { return nil, shorturls.ErrShortURLBadRequest.Errorf("invalid UID: %s", uid) } // Check if the UID already exists existingShortURL, err := s.SQLStore.Get(ctx, user, uid) if err != nil { if !shorturls.ErrShortURLNotFound.Is(err) { return nil, shorturls.ErrShortURLInternal.Errorf("failed to check existing short URL: %w", err) } } if existingShortURL != nil { // If the UID already exists, we return an error return nil, shorturls.ErrShortURLConflict.Errorf("short URL with UID '%s' already exists", uid) } } now := time.Now().Unix() shortURL := shorturls.ShortUrl{ OrgId: user.GetOrgID(), Uid: uid, Path: relPath, CreatedAt: now, } shortURL.CreatedBy, _ = user.GetInternalID() if err := s.SQLStore.Insert(ctx, &shortURL); err != nil { return nil, shorturls.ErrShortURLInternal.Errorf("failed to insert shorturl: %w", err) } return &shortURL, nil } func (s ShortURLService) DeleteStaleShortURLs(ctx context.Context, cmd *shorturls.DeleteShortUrlCommand) error { return s.SQLStore.Delete(ctx, cmd) } func (s ShortURLService) ConvertShortURLToDTO(shortURL *shorturls.ShortUrl, appURL string) *dtos.ShortURL { url := fmt.Sprintf("%s/goto/%s?orgId=%d", strings.TrimSuffix(appURL, "/"), shortURL.Uid, shortURL.OrgId) return &dtos.ShortURL{ UID: shortURL.Uid, URL: url, } }