Skip to content
Closed
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ mobile/openapi/.openapi-generator/FILES
open-api/typescript-sdk/build
mobile/android/fastlane/report.xml
mobile/ios/fastlane/report.xml

immich-app/
33 changes: 15 additions & 18 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name: immich-dev
services:
immich-server:
container_name: immich_server
command: ['/usr/src/app/bin/immich-dev']
command: [ '/usr/src/app/bin/immich-dev' ]
image: immich-server-dev:latest
# extends:
# file: hwaccel.transcoding.yml
Expand Down Expand Up @@ -58,7 +58,7 @@ services:
image: immich-web-dev:latest
build:
context: ../web
command: ['/usr/src/app/bin/immich-web']
command: [ '/usr/src/app/bin/immich-web' ]
env_file:
- .env
ports:
Expand Down Expand Up @@ -125,23 +125,19 @@ services:
interval: 5m
start_interval: 30s
start_period: 5m
command:
[
'postgres',
'-c',
'shared_preload_libraries=vectors.so',
'-c',
'search_path="$$user", public, vectors',
'-c',
'logging_collector=on',
'-c',
'max_wal_size=2GB',
'-c',
'shared_buffers=512MB',
'-c',
'wal_compression=on',
]
command: [ 'postgres', '-c', 'shared_preload_libraries=vectors.so', '-c', 'search_path="$$user", public, vectors', '-c', 'logging_collector=on', '-c', 'max_wal_size=2GB', '-c', 'shared_buffers=512MB', '-c', 'wal_compression=on' ]

pgadmin:
image: dpage/pgadmin4
container_name: pgadmin4_container
restart: always
ports:
- "8888:80"
environment:
PGADMIN_DEFAULT_EMAIL: pontus.sjo@live.com
PGADMIN_DEFAULT_PASSWORD: admin
volumes:
- pgadmin-data:/var/lib/pgadmin
# set IMMICH_METRICS=true in .env to enable metrics
# immich-prometheus:
# container_name: immich_prometheus
Expand All @@ -167,3 +163,4 @@ volumes:
model-cache:
prometheus-data:
grafana-data:
pgadmin-data:
103 changes: 103 additions & 0 deletions install
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bash
set -o nounset
set -o pipefail

create_immich_directory() {
local -r Tgt='./immich-app'
echo "Creating Immich directory..."
if [[ -e $Tgt ]]; then
echo "Found existing directory $Tgt, will overwrite YAML files"
else
mkdir "$Tgt" || return
fi
cd "$Tgt" || return 1
}

download_docker_compose_file() {
echo "Downloading docker-compose.yml..."
"${Curl[@]}" "$RepoUrl"/docker-compose.yml -o ./docker-compose.yml
}

download_dot_env_file() {
echo "Downloading .env file..."
"${Curl[@]}" "$RepoUrl"/example.env -o ./.env
}

generate_random_password() {
echo "Generate random password for .env file..."
rand_pass=$(echo "$RANDOM$(date)$RANDOM" | sha256sum | base64 | head -c10)
if [ -z "$rand_pass" ]; then
sed -i -e "s/DB_PASSWORD=postgres/DB_PASSWORD=postgres${RANDOM}${RANDOM}/" ./.env
else
sed -i -e "s/DB_PASSWORD=postgres/DB_PASSWORD=${rand_pass}/" ./.env
fi
}

start_docker_compose() {
echo "Starting Immich's docker containers"

if ! docker compose >/dev/null 2>&1; then
echo "failed to find 'docker compose'"
return 1
fi

if ! docker compose up --remove-orphans -d; then
echo "Could not start. Check for errors above."
return 1
fi
show_friendly_message
}

show_friendly_message() {
local ip_address
ip_address=$(hostname -I | awk '{print $1}')
cat <<EOF
Successfully deployed Immich!
You can access the website at http://$ip_address:2283 and the server URL for the mobile app is http://$ip_address:2283/api
---------------------------------------------------
If you want to configure custom information of the server, including the database, Redis information, or the backup (or upload) location, etc.

1. First bring down the containers with the command 'docker compose down' in the immich-app directory,

2. Then change the information that fits your needs in the '.env' file,

3. Finally, bring the containers back up with the command 'docker compose up --remove-orphans -d' in the immich-app directory
EOF
}

# MAIN
main() {
echo "Starting Immich installation..."
local -r RepoUrl='https://github.com/immich-app/immich/releases/latest/download'
local -a Curl
if command -v curl >/dev/null; then
Curl=(curl -fsSL)
else
echo 'no curl binary found; please install curl and try again'
return 14
fi

create_immich_directory || {
echo 'error creating Immich directory'
return 10
}
download_docker_compose_file || {
echo 'error downloading Docker Compose file'
return 11
}
download_dot_env_file || {
echo 'error downloading .env'
return 12
}
generate_random_password
start_docker_compose || {
echo 'error starting Docker'
return 13
}
return 0
}

main
Exit=$?
[[ $Exit == 0 ]] || echo "There was an error installing Immich. Exit code: $Exit. Please provide these logs when asking for assistance."
exit "$Exit"
1 change: 1 addition & 0 deletions key.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
wO6MTIOvLlJXdDW2zp9IDa3aQwhjUil5Jd1HvdRI0
13 changes: 10 additions & 3 deletions mobile/openapi/lib/api/albums_api.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions open-api/immich-openapi-specs.json
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,14 @@
"type": "string"
}
},
{
"name": "esekShared",
"required": false,
"in": "query",
"schema": {
"type": "boolean"
}
},
{
"name": "shared",
"required": false,
Expand Down
6 changes: 6 additions & 0 deletions open-api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion open-api/typescript-sdk/src/fetch-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1454,15 +1454,17 @@ export function restoreUserAdmin({ id }: {
method: "POST"
}));
}
export function getAllAlbums({ assetId, shared }: {
export function getAllAlbums({ assetId, esekShared, shared }: {
assetId?: string;
esekShared?: boolean;
shared?: boolean;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AlbumResponseDto[];
}>(`/albums${QS.query(QS.explode({
assetId,
esekShared,
shared
}))}`, {
...opts
Expand Down
1 change: 1 addition & 0 deletions server/src/controllers/album.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export class AlbumController {
@Get()
@Authenticated({ permission: Permission.ALBUM_READ })
getAllAlbums(@Auth() auth: AuthDto, @Query() query: GetAlbumsDto): Promise<AlbumResponseDto[]> {
console.log(query)
return this.service.getAll(auth, query);
}

Expand Down
3 changes: 3 additions & 0 deletions server/src/dtos/album.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ export class GetAlbumsDto {
*/
shared?: boolean;

@ValidateBoolean({optional: true})
esekShared?: boolean;

/**
* Only returns albums that contain the asset
* Ignores the shared parameter
Expand Down
3 changes: 3 additions & 0 deletions server/src/entities/album.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ export class AlbumEntity {
@OneToMany(() => SharedLinkEntity, (link) => link.album)
sharedLinks!: SharedLinkEntity[];

@Column({ default: false})
esekShared!: boolean

@Column({ default: true })
isActivityEnabled!: boolean;

Expand Down
1 change: 1 addition & 0 deletions server/src/interfaces/album.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface IAlbumRepository extends IBulkAsset {
getOwned(ownerId: string): Promise<AlbumEntity[]>;
getShared(ownerId: string): Promise<AlbumEntity[]>;
getNotShared(ownerId: string): Promise<AlbumEntity[]>;
getEsekShared(): Promise<AlbumEntity[]>;
restoreAll(userId: string): Promise<void>;
softDeleteAll(userId: string): Promise<void>;
deleteAll(userId: string): Promise<void>;
Expand Down
10 changes: 7 additions & 3 deletions server/src/middleware/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import { UAParser } from 'ua-parser-js';

type AdminRoute = { admin?: true };
type SharedLinkRoute = { sharedLink?: true };
type AuthenticatedOptions = { permission?: Permission } & (AdminRoute | SharedLinkRoute);
type EsekShareRoute = { esekShare?: true};
type AuthenticatedOptions = { permission?: Permission } & (AdminRoute | SharedLinkRoute) & EsekShareRoute;

export const Authenticated = (options?: AuthenticatedOptions): MethodDecorator => {
const decorators: MethodDecorator[] = [
Expand All @@ -32,6 +33,8 @@ export const Authenticated = (options?: AuthenticatedOptions): MethodDecorator =
decorators.push(ApiQuery({ name: ImmichQuery.SHARED_LINK_KEY, type: String, required: false }));
}

// TODO: evaluate if needed

return applyDecorators(...decorators);
};

Expand Down Expand Up @@ -85,14 +88,15 @@ export class AuthGuard implements CanActivate {
const {
admin: adminRoute,
sharedLink: sharedLinkRoute,
esekShare: esekShareRoute,
permission,
} = { sharedLink: false, admin: false, ...options };
} = { sharedLink: false, esekShare: false, admin: false, ...options };
const request = context.switchToHttp().getRequest<AuthRequest>();

request.user = await this.authService.authenticate({
headers: request.headers,
queryParams: request.query as Record<string, string>,
metadata: { adminRoute, sharedLinkRoute, permission, uri: request.path },
metadata: { adminRoute, esekShareRoute, sharedLinkRoute, permission, uri: request.path },
});

return true;
Expand Down
14 changes: 14 additions & 0 deletions server/src/migrations/1729088299829-add_esek_share.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddEsekShare1729088299829 implements MigrationInterface {
name = 'AddEsekShare1729088299829'

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "albums" ADD "esekShared" boolean NOT NULL DEFAULT false`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "albums" DROP COLUMN "esekShared"`);
}

}
Loading