diff --git a/.drone.yml b/.drone.yml index 3fd4581..c01c09f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -108,52 +108,6 @@ steps: - VERSION=${DRONE_TAG} - VITE_API_URL=${VITE_API_URL:-/api} - # -------- NEW: Create Gitea Release -------- - - name: gitea-release - image: plugins/gitea-release - when: - event: tag - settings: - api_key: - from_secret: GITEA_TOKEN - base_url: https://gitea.local.nothaft.cloud - files: [] - title: PicPeak ${DRONE_TAG} - note: | - # PicPeak ${DRONE_TAG} - - ## ๐Ÿณ Docker Images - - This release includes Docker images published to local registry: - - ```bash - # Backend - docker pull registry.local.nothaft.cloud/picpeak-backend:${DRONE_TAG} - docker pull registry.local.nothaft.cloud/picpeak-backend:latest - - # Frontend - docker pull registry.local.nothaft.cloud/picpeak-frontend:${DRONE_TAG} - docker pull registry.local.nothaft.cloud/picpeak-frontend:latest - ``` - - ## ๐Ÿ“ฆ What's New - - See the [README](https://gitea.nothaft.cloud/paul/picpeak#readme) for features and documentation. - - ## ๐Ÿš€ Quick Start - - ```bash - # Clone and deploy - git clone https://gitea.nothaft.cloud/paul/picpeak.git - cd picpeak - - # Use the tagged version - docker-compose -f docker-compose.prod.yml up -d - ``` - - --- - - For detailed deployment instructions, see the Deployment Guide in the repository. trigger: event: diff --git a/.gitea/workflows/mirror-to-github.yml b/.gitea/workflows/mirror-to-github.yml index ecf2be5..47a6eee 100644 --- a/.gitea/workflows/mirror-to-github.yml +++ b/.gitea/workflows/mirror-to-github.yml @@ -10,120 +10,18 @@ jobs: mirror: runs-on: ubuntu-latest steps: - - name: Checkout repository with full history + - name: Checkout repository uses: actions/checkout@v3 with: - fetch-depth: 0 # Full history needed for finding the commit + fetch-depth: 0 # Full history for proper mirroring - name: Setup Git run: | git config --global user.name "the-luap" git config --global user.email "paul-nothaft@hotmail.de" - - name: Debug - Show current branch and status - run: | - echo "Current branch:" - git branch -a - echo "Git status:" - git status - echo "Remote info:" - git remote -v - echo "Checking target commit exists:" - git show --oneline 7aca927937 || echo "Target commit not found!" - - - name: Create completely new history from specific commit - run: | - TARGET_COMMIT="7aca927937" - - # Verify the target commit exists - if ! git cat-file -e $TARGET_COMMIT^{commit}; then - echo "ERROR: Target commit $TARGET_COMMIT does not exist!" - exit 1 - fi - - echo "โœ… Target commit found: $(git log --oneline -1 $TARGET_COMMIT)" - - # Clean up any existing github-mirror branch - git branch -D github-mirror || true - - # Create a completely new orphan branch (no history) - git checkout --orphan github-mirror - - # Clear the staging area completely - git rm -rf . || true - - # Get the file tree from the target commit and create initial commit - echo "Creating new history starting from $TARGET_COMMIT..." - git read-tree $TARGET_COMMIT - git commit -m "Initial commit - imported from $(git log --oneline -1 $TARGET_COMMIT)" - - echo "โœ… Created new initial commit: $(git log --oneline -1)" - - # Now get all commits after the target commit and apply their changes - COMMITS_AFTER_TARGET=$(git rev-list --reverse --no-merges $TARGET_COMMIT..main) - - if [ -n "$COMMITS_AFTER_TARGET" ]; then - echo "๐Ÿ“‹ Applying changes from commits after $TARGET_COMMIT (excluding Claude commits):" - - for commit in $COMMITS_AFTER_TARGET; do - # Get the commit author name - COMMIT_AUTHOR_NAME=$(git log --format="%an" -n 1 $commit) - - # Skip commits by Claude - if [ "$COMMIT_AUTHOR_NAME" = "Claude" ]; then - echo "โš ๏ธ Skipping commit by Claude: $(git log --oneline -1 $commit)" - continue - fi - - echo "Processing: $(git log --oneline -1 $commit)" - - # Get the commit message and author info - COMMIT_MSG=$(git log --format="%B" -n 1 $commit) - COMMIT_AUTHOR=$(git log --format="%an <%ae>" -n 1 $commit) - COMMIT_DATE=$(git log --format="%ad" -n 1 $commit) - - # Apply the changes from this commit - if git diff-tree --no-commit-id --name-only -r $commit | xargs -I {} git show $commit:{} > /dev/null 2>&1; then - # Apply file changes - git checkout $commit -- . || true - - # Stage all changes - git add -A - - # Only commit if there are changes - if ! git diff --cached --quiet; then - # Create new commit with original metadata but new SHA - GIT_AUTHOR_NAME=$(echo "$COMMIT_AUTHOR" | cut -d'<' -f1 | xargs) - GIT_AUTHOR_EMAIL=$(echo "$COMMIT_AUTHOR" | cut -d'<' -f2 | cut -d'>' -f1) - GIT_AUTHOR_DATE="$COMMIT_DATE" - - export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE - git commit -m "$COMMIT_MSG" - echo "โœ… Applied changes as new commit: $(git log --oneline -1)" - else - echo "โš ๏ธ No changes to commit for $commit" - fi - else - echo "โš ๏ธ Skipping problematic commit $commit" - fi - done - - echo "โœ… Finished creating new history" - else - echo "โœ… No commits after target commit - history starts fresh" - fi - - echo "" - echo "=== New History Summary ===" - echo "Total commits in new history: $(git rev-list --count github-mirror)" - echo "History starts with: $(git log --oneline --reverse | head -1)" - echo "Latest commit: $(git log --oneline -1)" - - name: Remove sensitive files and directories run: | - # Switch to the github-mirror branch - git checkout github-mirror - echo "Current files before cleanup:" ls -la | head -10 || true echo "..." @@ -164,18 +62,6 @@ jobs: echo "Final file structure (top level):" ls -la | head -10 || true - - name: Verify completely new history - run: | - git checkout github-mirror - echo "=== Final History Verification ===" - echo "Total commits in new github-mirror branch: $(git rev-list --count github-mirror)" - echo "" - echo "Complete commit history (should start from target commit content):" - git log --oneline --reverse - echo "" - echo "โš ๏ธ Note: This is a completely NEW history with new commit SHAs" - echo "๐Ÿ” Original target commit content preserved but with new commit ID" - - name: Check GitHub token env: GITHUBTOKEN: ${{ secrets.GITHUBTOKEN }} @@ -187,13 +73,10 @@ jobs: echo "GitHub token is available (length: ${#GITHUBTOKEN})" fi - - name: Force push completely new history to GitHub + - name: Push to GitHub env: GITHUBTOKEN: ${{ secrets.GITHUBTOKEN }} run: | - # Switch to github-mirror branch - git checkout github-mirror - # Remove existing github remote if it exists git remote remove github || true @@ -204,17 +87,13 @@ jobs: echo "GitHub remote added:" git remote -v - # Force push the completely new history to GitHub main - echo "๐Ÿ”ฅ FORCE PUSHING completely new history to GitHub..." - echo "โš ๏ธ This will COMPLETELY REPLACE all history on GitHub!" - git push github github-mirror:main --force - echo "โœ… Force push completed - GitHub now has completely new history!" + # Push to GitHub main branch + echo "Pushing to GitHub..." + git push github main --force + echo "โœ… Push to GitHub completed!" - name: Workflow completed run: | echo "โœ… Mirror to GitHub workflow completed successfully!" - echo "๐Ÿ”ฅ COMPLETE HISTORY REPLACEMENT: GitHub now has entirely new history" - echo "๐Ÿ“Š History starts from commit content: 7aca927937" - echo "๐Ÿ” Check https://github.com/the-luap/picpeak to verify the new history" - echo "๐Ÿ“ˆ Total commits pushed: $(git rev-list --count github-mirror)" - echo "๐Ÿ†• All commit SHAs are NEW - no connection to previous history" \ No newline at end of file + echo "๐Ÿ“Š Repository mirrored to: https://github.com/the-luap/picpeak" + echo "๐Ÿ”’ Sensitive files have been removed from the mirror" \ No newline at end of file diff --git a/backend/src/routes/adminPhotos.js b/backend/src/routes/adminPhotos.js index 4dcb953..5336da6 100644 --- a/backend/src/routes/adminPhotos.js +++ b/backend/src/routes/adminPhotos.js @@ -447,9 +447,14 @@ router.delete('/:eventId/photos/:photoId', adminAuth, async (req, res) => { if (photo.thumbnail_path) { const thumbPath = path.join(storagePath, 'events/active', photo.thumbnail_path); try { + // Check if file exists before attempting to delete + await fs.access(thumbPath); await fs.unlink(thumbPath); } catch (error) { - console.error('Error deleting thumbnail:', error); + // Only log if it's not a "file not found" error + if (error.code !== 'ENOENT') { + console.error('Error deleting thumbnail:', error); + } } } @@ -534,9 +539,14 @@ router.post('/:eventId/photos/bulk-delete', adminAuth, async (req, res) => { if (photo.thumbnail_path) { const thumbPath = path.join(storagePath, photo.thumbnail_path); try { + // Check if file exists before attempting to delete + await fs.access(thumbPath); await fs.unlink(thumbPath); } catch (error) { - console.error('Error deleting thumbnail:', error); + // Only log if it's not a "file not found" error + if (error.code !== 'ENOENT') { + console.error('Error deleting thumbnail:', error); + } } } } diff --git a/clean-git-history.sh b/clean-git-history.sh new file mode 100755 index 0000000..5b5ca9c --- /dev/null +++ b/clean-git-history.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# Script to clean git history - removes all commits before July 17, 2025 +# WARNING: This is destructive and will rewrite history! + +set -e + +echo "โš ๏ธ WARNING: This script will permanently rewrite git history!" +echo "โš ๏ธ All commits before July 17, 2025 will be removed." +echo "โš ๏ธ This action cannot be undone!" +echo "" +read -p "Are you sure you want to continue? (type 'yes' to proceed): " confirmation + +if [ "$confirmation" != "yes" ]; then + echo "Operation cancelled." + exit 1 +fi + +# Create backup branch +echo "Creating backup branch..." +git checkout -b backup-before-cleanup-$(date +%Y%m%d-%H%M%S) +git checkout main + +# Find the first commit on or after July 17, 2025 +echo "Finding first commit after July 17, 2025..." +FIRST_COMMIT=$(git log --since="2025-07-17" --reverse --format="%H" | head -1) + +if [ -z "$FIRST_COMMIT" ]; then + echo "ERROR: No commits found after July 17, 2025" + exit 1 +fi + +echo "First commit to keep: $FIRST_COMMIT" +echo "Commit details: $(git log --oneline -1 $FIRST_COMMIT)" + +# Get all commits we want to keep +COMMITS_TO_KEEP=$(git log --since="2025-07-17" --reverse --format="%H") +COMMIT_COUNT=$(echo "$COMMITS_TO_KEEP" | wc -l) +echo "Total commits to preserve: $COMMIT_COUNT" + +# Create new orphan branch +echo "Creating new clean history..." +git checkout --orphan new-main + +# Clean the working directory +git rm -rf . || true + +# Get the tree from the first commit +git checkout $FIRST_COMMIT -- . + +# Create new initial commit with same content but new message +ORIGINAL_MESSAGE=$(git log --format="%B" -1 $FIRST_COMMIT) +ORIGINAL_AUTHOR=$(git log --format="%an <%ae>" -1 $FIRST_COMMIT) +ORIGINAL_DATE=$(git log --format="%ad" -1 $FIRST_COMMIT) + +GIT_AUTHOR_NAME=$(echo "$ORIGINAL_AUTHOR" | cut -d'<' -f1 | xargs) +GIT_AUTHOR_EMAIL=$(echo "$ORIGINAL_AUTHOR" | cut -d'<' -f2 | cut -d'>' -f1) +GIT_AUTHOR_DATE="$ORIGINAL_DATE" +export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE + +git add -A +git commit -m "Initial commit - Project start (July 17, 2025) + +Original: $ORIGINAL_MESSAGE" + +# Cherry-pick remaining commits +echo "Applying remaining commits..." +REMAINING_COMMITS=$(git log --since="2025-07-17" --reverse --format="%H" $FIRST_COMMIT..main) + +if [ -n "$REMAINING_COMMITS" ]; then + for commit in $REMAINING_COMMITS; do + echo "Applying: $(git log --oneline -1 $commit)" + git cherry-pick $commit || { + echo "ERROR: Failed to cherry-pick $commit" + echo "You may need to resolve conflicts and continue manually" + exit 1 + } + done +fi + +echo "" +echo "โœ… New history created successfully!" +echo "Total commits in new history: $(git rev-list --count HEAD)" +echo "" +echo "To finalize the cleanup, run these commands:" +echo " git branch -D main" +echo " git branch -m main" +echo " git push origin main --force" +echo "" +echo "โš ๏ธ WARNING: Force pushing will overwrite the remote repository!" +echo "โš ๏ธ Make sure you have a backup and all team members are aware!" \ No newline at end of file diff --git a/frontend/src/components/admin/AdminPhotoGrid.tsx b/frontend/src/components/admin/AdminPhotoGrid.tsx index e627a3f..eaad59a 100644 --- a/frontend/src/components/admin/AdminPhotoGrid.tsx +++ b/frontend/src/components/admin/AdminPhotoGrid.tsx @@ -23,7 +23,7 @@ export const AdminPhotoGrid: React.FC = ({ const [selectedPhotos, setSelectedPhotos] = useState>(new Set()); const [isSelectionMode, setIsSelectionMode] = useState(false); const [isDeleting, setIsDeleting] = useState(false); - const [deletingPhotoId, setDeletingPhotoId] = useState(null); + const [deletingPhotos, setDeletingPhotos] = useState>(new Set()); const handlePhotoSelect = (photoId: number, e?: React.MouseEvent) => { if (e) { @@ -54,15 +54,18 @@ export const AdminPhotoGrid: React.FC = ({ return; } - setDeletingPhotoId(photo.id); + setDeletingPhotos(prev => new Set(prev).add(photo.id)); try { await photosService.deletePhoto(eventId, photo.id); toast.success('Photo deleted successfully'); onPhotosDeleted(); } catch (error) { toast.error('Failed to delete photo'); - } finally { - setDeletingPhotoId(null); + setDeletingPhotos(prev => { + const newSet = new Set(prev); + newSet.delete(photo.id); + return newSet; + }); } }; @@ -75,14 +78,18 @@ export const AdminPhotoGrid: React.FC = ({ } setIsDeleting(true); + const selectedIds = Array.from(selectedPhotos); + setDeletingPhotos(new Set(selectedIds)); + try { - await photosService.deletePhotos(eventId, Array.from(selectedPhotos)); + await photosService.deletePhotos(eventId, selectedIds); toast.success(`${count} photo${count > 1 ? 's' : ''} deleted successfully`); setSelectedPhotos(new Set()); setIsSelectionMode(false); onPhotosDeleted(); } catch (error) { toast.error('Failed to delete photos'); + setDeletingPhotos(new Set()); } finally { setIsDeleting(false); } @@ -155,13 +162,15 @@ export const AdminPhotoGrid: React.FC = ({ {/* Photo Grid */}
- {photos.map((photo, index) => ( -
isSelectionMode ? handlePhotoSelect(photo.id) : onPhotoClick(photo, index)} + {photos.map((photo, index) => { + const isDeleting = deletingPhotos.has(photo.id); + return ( +
!isDeleting && (isSelectionMode ? handlePhotoSelect(photo.id) : onPhotoClick(photo, index))} > {/* Selection Checkbox */} {isSelectionMode && ( @@ -219,8 +228,8 @@ export const AdminPhotoGrid: React.FC = ({ @@ -238,7 +247,8 @@ export const AdminPhotoGrid: React.FC = ({
)}
- ))} + ); + })}
{photos.length === 0 && ( diff --git a/frontend/src/components/admin/PhotoUpload.tsx b/frontend/src/components/admin/PhotoUpload.tsx index d82f26a..c338735 100644 --- a/frontend/src/components/admin/PhotoUpload.tsx +++ b/frontend/src/components/admin/PhotoUpload.tsx @@ -256,7 +256,7 @@ export const PhotoUpload: React.FC = ({ eventId, onUploadCompl
{t('upload.uploading')} - {totalChunks > 1 && ` (${t('common.chunk') || 'Chunk'} ${currentChunk}/${totalChunks})`} + {totalChunks > 1 && ` (${t('common.chunk')} ${currentChunk}/${totalChunks})`} {uploadProgress}%
@@ -268,7 +268,7 @@ export const PhotoUpload: React.FC = ({ eventId, onUploadCompl {totalChunks > 1 && (

- {t('upload.uploadingChunks') || `Uploading ${selectedFiles.length} files in ${totalChunks} batches...`} + {t('upload.uploadingChunks', { count: selectedFiles.length, total: totalChunks })}

)} diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 2ae2b26..e398217 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -35,7 +35,8 @@ "days": "Tage", "customize": "Anpassen", "hide": "Ausblenden", - "unknown": "Unbekannt" + "unknown": "Unbekannt", + "chunk": "Teil" }, "upload": { "photoCategory": "Fotokategorie", @@ -51,7 +52,8 @@ "uploadPhotos": "Fotos hochladen", "maxFilesReached": "Maximal 500 Dateien erlaubt", "someFilesSkipped": "Einige Dateien wurden รผbersprungen (500 Dateien Limit)", - "tooManyFiles": "Maximal 500 Dateien kรถnnen gleichzeitig hochgeladen werden" + "tooManyFiles": "Maximal 500 Dateien kรถnnen gleichzeitig hochgeladen werden", + "uploadingChunks": "Lade {{count}} Dateien in {{total}} Teilen hoch..." }, "navigation": { "dashboard": "Dashboard", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 0a65113..5832142 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -35,7 +35,8 @@ "days": "days", "customize": "Customize", "hide": "Hide", - "unknown": "Unknown" + "unknown": "Unknown", + "chunk": "Chunk" }, "upload": { "photoCategory": "Photo Category", @@ -51,7 +52,8 @@ "uploadPhotos": "Upload Photos", "maxFilesReached": "Maximum 500 files allowed", "someFilesSkipped": "Some files were skipped (500 file limit)", - "tooManyFiles": "Maximum 500 files can be uploaded at once" + "tooManyFiles": "Maximum 500 files can be uploaded at once", + "uploadingChunks": "Uploading {{count}} files in {{total}} batches..." }, "navigation": { "dashboard": "Dashboard",