Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix user e2e tests #194

Merged
merged 3 commits into from
Jun 6, 2022
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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ stage:
docker-compose -f ./docker/docker-compose.staging.yml up --build -V --remove-orphans

test-e2e:
docker-compose -f ./docker/docker-compose.test.yml --env-file ./docker/.env.test up --abort-on-container-exit --exit-code-from immich_server_test
docker-compose -f ./docker/docker-compose.test.yml --env-file ./docker/.env.test up --renew-anon-volumes --abort-on-container-exit --exit-code-from immich_server_test --remove-orphans

prod:
docker-compose -f ./docker/docker-compose.yml up --build -V --remove-orphans
Expand Down
10 changes: 8 additions & 2 deletions docker/.env.test
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
DB_HOSTNAME=immich_postgres_test
# Database
DB_HOSTNAME=immich_postgres_test
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_DATABASE_NAME=e2e_test

# Redis
REDIS_HOSTNAME=immich_redis_test

# Upload File Config
UPLOAD_LOCATION=./upload

Expand All @@ -13,4 +16,7 @@ JWT_SECRET=randomstringthatissolongandpowerfulthatnoonecanguess
# MAPBOX
## ENABLE_MAPBOX is either true of false -> if true, you have to provide MAPBOX_KEY
ENABLE_MAPBOX=false
MAPBOX_KEY=

# WEB
MAPBOX_KEY=
VITE_SERVER_ENDPOINT=http://localhost:2283
4 changes: 1 addition & 3 deletions docker/docker-compose.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,11 @@ services:
POSTGRES_DB: ${DB_DATABASE_NAME}
PG_DATA: /var/lib/postgresql/data
volumes:
- pgdata-test:/var/lib/postgresql/data
- /var/lib/postgresql/data
ports:
- 5432:5432
networks:
- immich_network_test

networks:
immich_network_test:
volumes:
pgdata-test:
2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js"
"typeorm": "node --require ts-node/register ./node_modules/typeorm/cli.js --config src/config/database.config.ts"
},
"dependencies": {
"@mapbox/mapbox-sdk": "^0.13.3",
Expand Down
42 changes: 23 additions & 19 deletions server/src/api-v1/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,32 @@ import { ImmichJwtService } from '../../modules/immich-jwt/immich-jwt.service';
import { JwtPayloadDto } from './dto/jwt-payload.dto';
import { SignUpDto } from './dto/sign-up.dto';
import * as bcrypt from 'bcrypt';
import { mapUser, User } from '../user/response-dto/user';

@Injectable()
export class AuthService {
constructor(
@InjectRepository(UserEntity)
private userRepository: Repository<UserEntity>,
private immichJwtService: ImmichJwtService,
) { }
) {}

private async validateUser(loginCredential: LoginCredentialDto): Promise<UserEntity> {
const user = await this.userRepository.findOne(
{ email: loginCredential.email },
{ select: ['id', 'email', 'password', 'salt', 'firstName', 'lastName', 'isAdmin', 'profileImagePath', 'isFirstLoggedIn'] },
{
select: [
'id',
'email',
'password',
'salt',
'firstName',
'lastName',
'isAdmin',
'profileImagePath',
'isFirstLoggedIn',
],
},
);

const isAuthenticated = await this.validatePassword(user.password, loginCredential.password, user.salt);
Expand Down Expand Up @@ -48,38 +61,29 @@ export class AuthService {
lastName: validatedUser.lastName,
isAdmin: validatedUser.isAdmin,
profileImagePath: validatedUser.profileImagePath,
isFirstLogin: validatedUser.isFirstLoggedIn
isFirstLogin: validatedUser.isFirstLoggedIn,
};
}


public async adminSignUp(signUpCrendential: SignUpDto) {
public async adminSignUp(signUpCredential: SignUpDto): Promise<User> {
const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } });

if (adminUser) {
throw new BadRequestException('The server already has an admin')
throw new BadRequestException('The server already has an admin');
}


const newAdminUser = new UserEntity();
newAdminUser.email = signUpCrendential.email;
newAdminUser.email = signUpCredential.email;
newAdminUser.salt = await bcrypt.genSalt();
newAdminUser.password = await this.hashPassword(signUpCrendential.password, newAdminUser.salt);
newAdminUser.firstName = signUpCrendential.firstName;
newAdminUser.lastName = signUpCrendential.lastName;
newAdminUser.password = await this.hashPassword(signUpCredential.password, newAdminUser.salt);
newAdminUser.firstName = signUpCredential.firstName;
newAdminUser.lastName = signUpCredential.lastName;
newAdminUser.isAdmin = true;

try {
const savedNewAdminUserUser = await this.userRepository.save(newAdminUser);

return {
id: savedNewAdminUserUser.id,
email: savedNewAdminUserUser.email,
firstName: savedNewAdminUserUser.firstName,
lastName: savedNewAdminUserUser.lastName,
createdAt: savedNewAdminUserUser.createdAt,
};

return mapUser(savedNewAdminUserUser);
} catch (e) {
Logger.error('e', 'signUp');
throw new InternalServerErrorException('Failed to register new admin user');
Expand Down
8 changes: 4 additions & 4 deletions server/src/api-v1/user/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ export class CreateUserDto {
lastName: string;

@IsOptional()
profileImagePath: string;
profileImagePath?: string;

@IsOptional()
isAdmin: boolean;
isAdmin?: boolean;

@IsOptional()
isFirstLoggedIn: boolean;
isFirstLoggedIn?: boolean;

@IsOptional()
id: string;
id?: string;
}
19 changes: 19 additions & 0 deletions server/src/api-v1/user/response-dto/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { UserEntity } from '../entities/user.entity';

export interface User {
id: string;
email: string;
firstName: string;
lastName: string;
createdAt: string;
}

export function mapUser(entity: UserEntity): User {
return {
id: entity.id,
email: entity.email,
firstName: entity.firstName,
lastName: entity.lastName,
createdAt: entity.createdAt,
};
}
49 changes: 17 additions & 32 deletions server/src/api-v1/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,27 @@ import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { UserEntity } from './entities/user.entity';
import * as bcrypt from 'bcrypt';
import sharp from 'sharp';
import { createReadStream, unlink, unlinkSync } from 'fs';
import { createReadStream } from 'fs';
import { Response as Res } from 'express';
import { mapUser, User } from './response-dto/user';

@Injectable()
export class UserService {
constructor(
@InjectRepository(UserEntity)
private userRepository: Repository<UserEntity>,
) { }
) {}

async getAllUsers(authUser: AuthUserDto, isAll: boolean) {

if (isAll) {
return await this.userRepository.find();
}

return await this.userRepository.find({
where: { id: Not(authUser.id) },
order: {
createdAt: 'DESC'
}
createdAt: 'DESC',
},
});
}

Expand All @@ -40,14 +39,12 @@ export class UserService {
users = await this.userRepository.find();
}


return {
userCount: users.length
}

userCount: users.length,
};
}

async createUser(createUserDto: CreateUserDto) {
async createUser(createUserDto: CreateUserDto): Promise<User> {
const user = await this.userRepository.findOne({ where: { email: createUserDto.email } });

if (user) {
Expand All @@ -62,18 +59,10 @@ export class UserService {
newUser.lastName = createUserDto.lastName;
newUser.isAdmin = false;


try {
const savedUser = await this.userRepository.save(newUser);

return {
id: savedUser.id,
email: savedUser.email,
firstName: savedUser.firstName,
lastName: savedUser.lastName,
createdAt: savedUser.createdAt,
};

return mapUser(savedUser);
} catch (e) {
Logger.error(e, 'Create new user');
throw new InternalServerErrorException('Failed to register new user');
Expand All @@ -84,7 +73,6 @@ export class UserService {
return bcrypt.hash(password, salt);
}


async updateUser(updateUserDto: UpdateUserDto) {
const user = await this.userRepository.findOne(updateUserDto.id);

Expand All @@ -100,10 +88,10 @@ export class UserService {
}

if (updateUserDto.isAdmin) {
const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } })
const adminUser = await this.userRepository.findOne({ where: { isAdmin: true } });

if (adminUser) {
throw new BadRequestException("Admin user exists")
throw new BadRequestException('Admin user exists');
}

user.isAdmin = true;
Expand All @@ -120,7 +108,6 @@ export class UserService {
isAdmin: updatedUser.isAdmin,
profileImagePath: updatedUser.profileImagePath,
};

} catch (e) {
Logger.error(e, 'Create new user');
throw new InternalServerErrorException('Failed to register new user');
Expand All @@ -130,13 +117,12 @@ export class UserService {
async createProfileImage(authUser: AuthUserDto, fileInfo: Express.Multer.File) {
try {
await this.userRepository.update(authUser.id, {
profileImagePath: fileInfo.path
})

profileImagePath: fileInfo.path,
});

return {
userId: authUser.id,
profileImagePath: fileInfo.path
profileImagePath: fileInfo.path,
};
} catch (e) {
Logger.error(e, 'Create User Profile Image');
Expand All @@ -146,7 +132,7 @@ export class UserService {

async getUserProfileImage(userId: string, res: Res) {
try {
const user = await this.userRepository.findOne({ id: userId })
const user = await this.userRepository.findOne({ id: userId });

if (!user.profileImagePath) {
// throw new BadRequestException('User does not have a profile image');
Expand All @@ -157,11 +143,10 @@ export class UserService {
res.set({
'Content-Type': 'image/jpeg',
});
const fileStream = createReadStream(user.profileImagePath)
const fileStream = createReadStream(user.profileImagePath);
return new StreamableFile(fileStream);
} catch (e) {
console.log("error getting user profile")
console.log('error getting user profile');
}

}
}
4 changes: 3 additions & 1 deletion server/src/config/database.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ export const databaseConfig: TypeOrmModuleOptions = {
database: process.env.DB_DATABASE_NAME,
entities: [__dirname + '/../**/*.entity.{js,ts}'],
synchronize: false,
migrations: [__dirname + '/../migration/*.js'],
migrations: [__dirname + '/../migration/*.{js,ts}'],
cli: {
migrationsDir: __dirname + '/../migration',
},
migrationsRun: true,
};

export default databaseConfig;
Loading