Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ nano .env
# Start with Docker Compose
docker compose up -d

# Access at http://localhost:3005
# Access at http://localhost:3000
```

Note on Docker file permissions (PUID/PGID)
Expand Down
4 changes: 2 additions & 2 deletions backend/migrations/core/001_init.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ exports.up = async function(knex) {
// Create default admin user if none exists
const adminExists = await knex('admin_users').first();
if (!adminExists) {
// Generate a secure random password
const generatedPassword = generateReadablePassword();
// Use ADMIN_PASSWORD from environment if set, otherwise generate a random one
const generatedPassword = process.env.ADMIN_PASSWORD || generateReadablePassword();
const passwordHash = await bcrypt.hash(generatedPassword, 12); // Increased rounds for better security

// Get admin credentials from environment or use defaults
Expand Down
47 changes: 29 additions & 18 deletions backend/scripts/create-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,39 @@ async function createAdmin() {
.orWhere('username', username)
.first();

if (existingUser) {
console.error(`Error: User with email "${email}" or username "${username}" already exists`);
process.exit(1);
}

// Hash password
const passwordHash = await bcrypt.hash(password, 10);

// Create admin user
await db('admin_users').insert({
username,
email,
password_hash: passwordHash,
is_active: true,
created_at: new Date(),
updated_at: new Date()
});
if (existingUser) {
// Update existing user's password
await db('admin_users')
.where('id', existingUser.id)
.update({
password_hash: passwordHash,
updated_at: new Date()
});

console.log(`✅ Admin user updated successfully!`);
console.log(` Email: ${existingUser.email}`);
console.log(` Username: ${existingUser.username}`);
console.log(` Password has been reset to the provided value`);
console.log(` Login URL: ${process.env.ADMIN_URL || 'http://localhost:3000'}/admin/login`);
} else {
// Create new admin user
await db('admin_users').insert({
username,
email,
password_hash: passwordHash,
is_active: true,
created_at: new Date(),
updated_at: new Date()
});

console.log(`✅ Admin user created successfully!`);
console.log(` Email: ${email}`);
console.log(` Username: ${username}`);
console.log(` Login URL: ${process.env.ADMIN_URL || 'http://localhost:3000'}/admin/login`);
console.log(`✅ Admin user created successfully!`);
console.log(` Email: ${email}`);
console.log(` Username: ${username}`);
console.log(` Login URL: ${process.env.ADMIN_URL || 'http://localhost:3000'}/admin/login`);
}

process.exit(0);
} catch (error) {
Expand Down
15 changes: 14 additions & 1 deletion frontend/src/components/admin/PhotoExportMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,20 @@ export const PhotoExportMenu: React.FC<PhotoExportMenuProps> = ({
if (selectedPhotoIds.length > 0) {
options.photo_ids = selectedPhotoIds;
} else if (filters) {
options.filter = filters;
// Convert camelCase filter keys to snake_case for backend
options.filter = {
min_rating: filters.minRating,
max_rating: filters.maxRating,
has_likes: filters.hasLikes,
min_likes: filters.minLikes,
has_favorites: filters.hasFavorites,
min_favorites: filters.minFavorites,
has_comments: filters.hasComments,
category_id: filters.categoryId,
logic: filters.logic,
sort: filters.sort,
order: filters.order,
};
}

exportMutation.mutate(options);
Expand Down
6 changes: 1 addition & 5 deletions frontend/src/features/settings/hooks/useSettingsState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,7 @@ export function useSettingsState() {
mutationFn: async () => {
const settingsData: Record<string, unknown> = {};
Object.entries(generalSettings).forEach(([key, value]) => {
if (key === 'date_format' && typeof value === 'object' && value.format) {
settingsData[`general_${key}`] = value.format;
} else {
settingsData[`general_${key}`] = value;
}
settingsData[`general_${key}`] = value;
});
return settingsService.updateSettings(settingsData);
},
Expand Down
5 changes: 1 addition & 4 deletions frontend/src/pages/admin/AdminLoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export const AdminLoginPage: React.FC = () => {
</div>
</div>

{/* Remember Me & Forgot Password */}
{/* Remember Me */}
<div className="flex items-center justify-between">
<label className="flex items-center">
<input
Expand All @@ -209,9 +209,6 @@ export const AdminLoginPage: React.FC = () => {
/>
<span className="ml-2 text-sm text-neutral-700">{t('adminLogin.rememberMe')}</span>
</label>
<a href="#" className="text-sm text-primary-600 hover:text-primary-700">
{t('adminLogin.forgotPassword')}
</a>
</div>

{/* reCAPTCHA */}
Expand Down