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

Upload own data backend #282

Merged
merged 21 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4eee565
feat(api): create model class for userfile
cephaschapa Jan 11, 2024
100918c
feat(api): created userfile migration
cephaschapa Jan 11, 2024
3e74d8e
feat(api): added file upload route, modified migration and models
cephaschapa Jan 16, 2024
f6aa52c
feat(api): added delete and get file by id routes
cephaschapa Jan 16, 2024
e890df7
feat(api): added download userfile route
cephaschapa Jan 16, 2024
c3aa663
fix(api): show right error message
cephaschapa Jan 17, 2024
35c7612
fix(api): include file_type, sector to userFile model, updated routes…
cephaschapa Jan 17, 2024
042bc68
feat(test): added userFile unit tests
cephaschapa Jan 19, 2024
d58ee38
fix: removed unused packages
cephaschapa Jan 19, 2024
e7d1c65
fix(api): moved userFile validation to validation file
cephaschapa Jan 19, 2024
389c689
fix: pr review changes
cephaschapa Jan 22, 2024
768497a
fix: added correct formData names, removed csv file
cephaschapa Jan 22, 2024
929b4c5
Merge
cephaschapa Jan 22, 2024
724f7c8
Merge branch 'develop' into feature/upload-own-data-backend
cephaschapa Jan 22, 2024
be8aaf6
Merge branch 'feature/upload-own-data-backend' of https://github.com/…
cephaschapa Jan 22, 2024
5e28486
fix(tests): resolve unit test errors
cephaschapa Jan 22, 2024
3c0b395
fix: code clean up
cephaschapa Jan 22, 2024
6eefe3b
fix(api): file acces changes, renamed columns in migration
cephaschapa Jan 24, 2024
d2d3ec9
fix(api): refined api response, fixed assertions in unit tests
cephaschapa Jan 24, 2024
d673144
fix(api): merge conflicts
cephaschapa Jan 24, 2024
97f4807
fix(api): mime download content type
cephaschapa Jan 24, 2024
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
10 changes: 5 additions & 5 deletions app/migrations/20240111123307-userfile.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,23 @@ module.exports = {
type: Sequelize.UUID,
primaryKey: true,
},
user_id: {
userId: {
type: Sequelize.UUID,
allowNull: true,
references: {
model:'User',
key: 'user_id'
}
},
file_reference: {
fileReference: {
type: Sequelize.STRING,
allowNull: true
},
data: {
type: Sequelize.BLOB,
allowNull: true,
},
file_type: {
fileType: {
type: Sequelize.STRING,
allowNull: true
},
Expand All @@ -40,7 +40,7 @@ module.exports = {
type: Sequelize.STRING,
allowNull: true
},
gpc_ref_no: {
gpcRefNo: {
type: Sequelize.STRING,
allowNull: true
},
Expand All @@ -50,7 +50,7 @@ module.exports = {
allowNull: true,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
},
last_updated: {
lastUpdated: {
type: Sequelize.DATE,
allowNull: true,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP'),
Expand Down
3 changes: 2 additions & 1 deletion app/src/app/[lng]/data/[step]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ import { logger } from "@/services/logger";

function getMailURI(locode?: string, sector?: string, year?: number): string {
const emails =
process.env.NEXT_PUBLIC_SUPPORT_EMAILS || "[email protected],[email protected]";
process.env.NEXT_PUBLIC_SUPPORT_EMAILS ||
"[email protected],[email protected]";
return `mailto://${emails}?subject=Missing third party data sources&body=City: ${locode}%0ASector: ${sector}%0AYear: ${year}`;
}

Expand Down
18 changes: 5 additions & 13 deletions app/src/app/api/v0/user/[user]/file/[file]/download-file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,10 @@ export const GET = apiHandler(
_req: Request,
context: { session?: Session; params: Record<string, string> },
) => {
const userId = context.params.user;
if (!context.session) {
throw new createHttpError.Unauthorized("Unauthorized");
}

const user = await db.models.User.findOne({
attributes: ["userId"],
where: {
userId: userId,
},
});
if (!user) {
throw new createHttpError.NotFound("File does not belong to this user");
}

const userFile = await db.models.UserFile.findOne({
where: {
id: context.params.file,
Expand All @@ -34,13 +23,16 @@ export const GET = apiHandler(
throw new createHttpError.NotFound("User file not found");
}

if (!userFile.userId)
throw new createHttpError.NotFound("file does not belong to this user");

let body: Buffer | undefined;
let headers: Record<string, string> | null = null;

body = userFile.data;
headers = {
"Content-Type": "application/vnd.ms-excel",
"Content-Disposition": `attachment; filename="${userFile.id}.${userFile.file_type}"`,
"Content-Type": `application/${userFile.fileType}`,
"Content-Disposition": `attachment; filename="${userFile.id}.${userFile.fileType}"`,
};

return new NextResponse(body, { headers });
Expand Down
29 changes: 5 additions & 24 deletions app/src/app/api/v0/user/[user]/file/[file]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,10 @@ export const GET = apiHandler(
_req: Request,
context: { session?: Session; params: Record<string, string> },
) => {
const userId = context.params.user;
if (!context.session) {
throw new createHttpError.Unauthorized("Unauthorized");
}

const user = await db.models.User.findOne({
attributes: ["userId"],
where: {
userId: userId,
},
});
if (!user) {
throw new createHttpError.NotFound("File does not belong to this user");
}

const userFile = await db.models.UserFile.findOne({
where: {
id: context.params.file,
Expand All @@ -34,6 +23,9 @@ export const GET = apiHandler(
throw new createHttpError.NotFound("User file not found");
}

if (!userFile.userId)
throw new createHttpError.NotFound("file does not belong to this user");

return NextResponse.json({ data: userFile });
},
);
Expand All @@ -43,22 +35,10 @@ export const DELETE = apiHandler(
_req: Request,
context: { session?: Session; params: Record<string, string> },
) => {
const userId = context.params.user;
if (!context.session) {
throw new createHttpError.Unauthorized("Unauthorized");
}

const user = await db.models.User.findOne({
attributes: ["userId"],
where: {
userId: userId,
},
});

if (!user) {
throw new createHttpError.NotFound("File does not belong to this user");
}

const userFile = await db.models.UserFile.findOne({
where: {
id: context.params.file,
Expand All @@ -68,7 +48,8 @@ export const DELETE = apiHandler(
if (!userFile) {
throw new createHttpError.NotFound("User file not found");
}

if (!userFile.userId)
throw new createHttpError.NotFound("file does not belong to this user");
await userFile.destroy();

return NextResponse.json({ data: userFile, deleted: true });
Expand Down
37 changes: 9 additions & 28 deletions app/src/app/api/v0/user/[user]/file/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,9 @@ export const GET = apiHandler(
throw new createHttpError.Unauthorized("Unauthorized");
}

const user = await db.models.User.findOne({
attributes: ["userId"],
where: {
userId: userId,
},
});
if (!user) {
throw new createHttpError.NotFound("User not found");
}

const userFiles = await db.models.UserFile.findAll({
where: {
userId: user.userId,
userId: userId,
},
});

Expand All @@ -56,20 +46,11 @@ export const POST = apiHandler(
throw new createHttpError.Unauthorized("Unauthorized");
}

const user = await db.models.User.findOne({
attributes: ["userId"],
where: {
userId: userId,
},
});

if (!user) {
throw new createHttpError.NotFound("User not allowed");
}

const formData = await req.formData();
const file = formData.get("data") as unknown as File;
if (!file) throw new createHttpError.BadRequest("File not found");
const file = formData?.get("data") as unknown as File;

if (!file)
throw new createHttpError.BadRequest("File not found, Please add a file");

const filename = file.name;

Expand All @@ -81,14 +62,14 @@ export const POST = apiHandler(
const buffer = Buffer.from(bytes);

const fileData = {
userId: formData.get("userId"),
file_reference: formData.get("file_reference"),
userId: userId,
fileReference: formData.get("fileReference"),
url: formData.get("url"),
data: buffer,
file_type: fileType,
fileType: fileType,
sector: formData.get("sector"),
status: formData.get("status"),
gpc_ref_no: formData.get("gpc_ref_no"),
gpcRefNo: formData.get("gpcRefNo"),
};

const body = createUserFileRequset.parse(fileData);
Expand Down
28 changes: 14 additions & 14 deletions app/src/models/UserFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { User, UserId } from "./User";
export interface UserFileAttributes {
id: string;
userId?: string;
file_reference?: string;
fileReference?: string;
data?: Buffer;
file_type?: string;
fileType?: string;
sector?: string;
status?: string;
url?: string;
gpc_ref_no?: string;
gpcRefNo?: string;
created?: Date;
lastUpdated?: Date;
}
Expand All @@ -20,13 +20,13 @@ export type UserFilePk = "id";
export type UserFileId = UserFile[UserFilePk];
export type UserFileOptionalAttributes =
| "userId"
| "file_reference"
| "fileReference"
| "data"
| "file_type"
| "fileType"
| "sector"
| "url"
| "status"
| "gpc_ref_no"
| "gpcRefNo"
| "created"
| "lastUpdated";
export type UserFileCreationAttributes = Optional<
Expand All @@ -40,13 +40,13 @@ export class UserFile
{
id!: string;
userId?: string | undefined;
file_reference?: string | undefined;
fileReference?: string | undefined;
data: Buffer | undefined;
file_type?: string | undefined;
fileType?: string | undefined;
sector?: string | undefined;
url?: string | undefined;
status: string | undefined;
gpc_ref_no?: string | undefined;
gpcRefNo?: string | undefined;
created?: Date | undefined;
lastUpdated?: Date | undefined;

Expand All @@ -72,17 +72,17 @@ export class UserFile
model: "User",
key: "user_id",
},
field: "user_id",
field: "userId",
},
file_reference: {
fileReference: {
type: DataTypes.STRING(255),
allowNull: true,
},
data: {
type: DataTypes.BLOB,
allowNull: true,
},
file_type: {
fileType: {
type: DataTypes.STRING(255),
allowNull: true,
},
Expand All @@ -98,7 +98,7 @@ export class UserFile
type: DataTypes.STRING(255),
allowNull: true,
},
gpc_ref_no: {
gpcRefNo: {
type: DataTypes.STRING(255),
allowNull: true,
},
Expand All @@ -109,7 +109,7 @@ export class UserFile
schema: "public",
timestamps: true,
createdAt: "created",
updatedAt: "last_updated",
updatedAt: "lastUpdated",
indexes: [
{
name: "UserFile_pkey",
Expand Down
2 changes: 1 addition & 1 deletion app/src/models/init-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ export function initModels(sequelize: Sequelize) {
});
User.belongsTo(User, { as: "organization", foreignKey: "organizationId" });
User.hasMany(User, { as: "users", foreignKey: "organizationId" });
User.hasOne(UserFile, { foreignKey: "userId", as: "user" });
User.hasMany(UserFile, { foreignKey: "userId", as: "user" });
UserFile.belongsTo(User, { as: "userFiles", foreignKey: "userId" });

return {
Expand Down
6 changes: 3 additions & 3 deletions app/src/util/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ export type CreatePopulationRequest = z.infer<typeof createPopulationRequest>;
// user file schema validation
export const createUserFileRequset = z.object({
userId: z.string().uuid().optional(),
file_reference: z.string().optional(),
fileReference: z.string().optional(),
data: z.any(),
file_type: z.string().optional(),
fileType: z.string().optional(),
sector: z.string().optional(),
url: z.string().url().optional(),
status: z.string().optional(),
gpc_ref_no: z.string().optional(),
gpcRefNo: z.string().optional(),
});

// Schema type definition
Expand Down
Loading