Skip to content

Commit

Permalink
first cut of the related api endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
fariedt authored and noumanahmads committed Jul 8, 2024
1 parent 487f90f commit f79b214
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 10 deletions.
89 changes: 87 additions & 2 deletions backend/backend/backend-src/lib/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import fs from 'fs'
import {
DynamoDBClient,
GetItemCommand,
PutItemCommand,
QueryCommand,
QueryCommandInput,
TransactGetItem,
Expand All @@ -25,6 +26,8 @@ const CONTRACT_EVENTS_TABLE = 's3m-contracts-events-dev'
const BALANCES_TABLE = 's3m-balances-dev'
const LASTFETCH_TABLE = 's3m-contracts-lastfetch-dev'

const RELATED_TABLE = 's3m-related-dev'

const s3client = new S3Client()
const dbclient = new DynamoDBClient()

Expand Down Expand Up @@ -53,8 +56,8 @@ export async function savePackageS3(address: string, package_name: string, zip_p
ContentType: 'application/zip',
})

const response = await s3client.send(command)
console.log(response)
await s3client.send(command)

return key
}

Expand All @@ -67,6 +70,7 @@ export async function deletePackageS3(address: string, package_name: string) {
Bucket: BUCKET,
Key: key,
})

return await s3client.send(command)
}
}
Expand Down Expand Up @@ -363,3 +367,84 @@ export async function getAddressEventsDB(address: string) {
if (response.Items === undefined) return []
else return response.Items?.map(item => unmarshall(item)) ?? []
}

export async function getRelatedDB(address: string): Promise<Record<string, string>[]> {
const command = new GetItemCommand({
TableName: RELATED_TABLE,
Key: {
address: {S: address},
},
ProjectionExpression: 'related',
})

const response = await dbclient.send(command)
if (response.Item === undefined) return []

return (unmarshall(response.Item) ?? {}).related
}

export async function createRelatedDB(address: string, data: IFace.IRelatedCreate) {
// get existing item, if any
const existing: Record<string, string>[] = await getRelatedDB(address)

const already = existing.filter(item => item.label == data.label)
if (already.length != 0) {
return {error: `label '${data.label}' already exists for address: ${already[0].address}`}
}

const command = new PutItemCommand({
TableName: RELATED_TABLE,
Item: marshall({
address: address,
related: existing.concat({label: data.label, address: data.address}),
}),
})

return await dbclient.send(command)
}

export async function deleteRelatedDB(address: string, data: IFace.IRelatedDelete) {
// get existing item, if any
const existing = await getRelatedDB(address)
if (existing.length == 0) return

const filtered = existing.filter(item => item.label != data.label)

const command = new PutItemCommand({
TableName: RELATED_TABLE,
Item: marshall({
address: address,
related: filtered,
}),
})

return await dbclient.send(command)
}

export async function modifyRelatedDB(address: string, data: IFace.IRelatedModify) {
// get existing item, if any
const existing = await getRelatedDB(address)
if (existing.length == 0) return

let item_address = ''
let item_idx = 0
for (let idx = 0; idx < existing.length; idx++) {
if (existing[idx].label == data.label) {
item_address = existing[idx].address
item_idx = idx
} else if (existing[idx].label == data.new_label) {
return {error: `label '${data.new_label}' already exists for address: ${existing[idx].address}`}
}
}
existing[item_idx].label = data.new_label

const command = new PutItemCommand({
TableName: RELATED_TABLE,
Item: marshall({
address: address,
related: existing,
}),
})

return await dbclient.send(command)
}
53 changes: 53 additions & 0 deletions backend/backend/backend-src/lib/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,59 @@ export async function validPublish(data: IFace.IPackageCreated): Promise<IFace.I
return {error: '', data: data}
}

export async function validRelatedCreate(data: IFace.IRelatedCreate): Promise<IFace.IValid> {
const stringFields = ['label', 'address']

for (const field of stringFields) {
if (!(field in data)) {
console.log(`missing field: ${field}`)
return {error: `missing field: ${field}`}
}
}

if (data.label.trim() == '') {
console.log('missing field: label')
return {error: 'missing field: label'}
}

if (!isValidAddress(data.address)) {
console.log(`invalid address: ${data.address}`)
return {error: `invalid address: ${data.address}`}
}

return {error: '', data: data}
}

export async function validRelatedDelete(data: IFace.IRelatedDelete): Promise<IFace.IValid> {
if (!('label' in data) || data.label == '') {
console.log('missing field: label')
return {error: 'missing field: label'}
}

return {error: '', data: data}
}

export async function validRelatedModify(data: IFace.IRelatedModify): Promise<IFace.IValid> {
const stringFields = ['label', 'new_label']

for (const field of stringFields) {
if (!(field in data)) {
console.log(`missing field: ${field}`)
return {error: `missing field: ${field}`}
}
}

if (data.label.trim() == '' || data.new_label.trim() == '') {
console.log('missing field')
return {error: 'missing field'}
} else {
data.label = data.label.trim()
data.new_label = data.new_label.trim()
}

return {error: '', data: data}
}

export function validIconRequest(data: IFace.IPackageIcon): IFace.IValid {
const stringFields = ['address', 'fileName']

Expand Down
17 changes: 17 additions & 0 deletions backend/backend/backend-src/lib/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ export interface IPackageCreated {
ticker_name?: string
}

export interface IRelatedItem {
label: string
address: string
}
export interface IRelatedCreate {
label: string
address: string
}
export interface IRelatedDelete {
label: string
}

export interface IRelatedModify {
label: string
new_label: string
}

export function reqToCreated(data: ICreatePackageRequest, s3key: string | undefined): IPackageCreated {
return {
address: data.address,
Expand Down
108 changes: 100 additions & 8 deletions backend/backend/backend-src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ app.post('/published', async (req: Request<{}, {}, IFace.IPackageCreated>, res)
res.status(200).json({status: 'ok', message: 'saved'})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: v.error,
})
}
Expand All @@ -94,7 +94,7 @@ app.post('/generateIconURL', async (req: Request<{}, {}, IFace.IPackageIcon>, re
res.status(200).json({status: 'ok', url: url})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: v.error,
})
}
Expand All @@ -109,7 +109,7 @@ app.get('/balances/:address', async (req, res) => {
})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: `invalid address: ${address}`,
})
}
Expand All @@ -124,7 +124,7 @@ app.get('/package-events/:address/:ticker', async (req, res) => {
})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: `invalid address: ${address}`,
})
}
Expand All @@ -139,7 +139,99 @@ app.get('/address-events/:address', async (req, res) => {
})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: `invalid address: ${address}`,
})
}
})

app.get('/related/:address', async (req, res) => {
const {address} = req.params
if (Checks.isValidAddress(address)) {
res.status(200).json({
status: 'ok',
related: await AWS.getRelatedDB(address),
})
} else {
res.status(400).json({
status: 'error',
message: `invalid address: ${address}`,
})
}
})

app.post('/related/:address', async (req, res) => {
const {address} = req.params
const v = await Checks.validRelatedCreate(req.body)
if (Checks.isValidAddress(address) && v.error === '') {
const ret = await AWS.createRelatedDB(address, v.data as IFace.IRelatedCreate)
if (ret !== undefined && 'error' in ret) {
res.status(400).json({
status: 'error',
message: ret.error,
})
} else {
res.status(200).json({
status: 'ok',
})
}
} else if (v.error != '') {
res.status(400).json({
status: 'error',
message: v.error,
})
} else {
res.status(400).json({
status: 'error',
message: `invalid address: ${address}`,
})
}
})

app.post('/related/:address/delete', async (req, res) => {
const {address} = req.params
const v = await Checks.validRelatedDelete(req.body)
if (Checks.isValidAddress(address) && v.error === '') {
await AWS.deleteRelatedDB(address, v.data as IFace.IRelatedDelete)
res.status(200).json({
status: 'ok',
})
} else if (v.error != '') {
res.status(400).json({
status: 'error',
message: v.error,
})
} else {
res.status(400).json({
status: 'error',
message: `invalid address: ${address}`,
})
}
})

app.post('/related/:address/modify', async (req, res) => {
const {address} = req.params
const v = await Checks.validRelatedModify(req.body)
if (Checks.isValidAddress(address) && v.error === '') {
const ret = await AWS.modifyRelatedDB(address, v.data as IFace.IRelatedModify)
if (ret !== undefined && 'error' in ret) {
res.status(400).json({
status: 'error',
message: ret.error,
})
} else {
res.status(200).json({
status: 'ok',
})
}
} else if (v.error != '') {
res.status(400).json({
status: 'error',
message: v.error,
})
} else {
res.status(400).json({
status: 'error',
message: `invalid address: ${address}`,
})
}
Expand All @@ -156,7 +248,7 @@ app.get('/packages/:address', async (req, res) => {
})
} else {
res.status(400).json({
error: 400,
status: 'error',
message: `invalid address: ${address}`,
})
}
Expand All @@ -174,14 +266,14 @@ app.get('/packages/:address/:param', async (req, res) => {

if (!addressCheck) {
return res.status(400).json({
error: 400,
status: 'error',
message: `invalid address: ${address}`,
})
}

if (tickerCheck !== '' && !digestCheck) {
return res.status(400).json({
error: 400,
status: 'error',
message: `invalid field: ${param}`,
})
}
Expand Down

0 comments on commit f79b214

Please sign in to comment.