Skip to content

Commit

Permalink
feat: added route for unregistering coord and doing correct checks wi…
Browse files Browse the repository at this point in the history
…th appropriate tests
  • Loading branch information
luandro committed Feb 8, 2025
1 parent bc962a8 commit 014b9c5
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 6 deletions.
17 changes: 17 additions & 0 deletions src/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ const DB_FILE = 'users.json'
* @typedef {Object} DBMethods
* @property {() => Coordinator[]} getCoordinators
* @property {(coordinator: Coordinator) => void} saveCoordinator
* @property {(phoneNumber: string) => void} deleteCoordinatorByPhone
* @property {(phoneNumber: string) => Coordinator|null} findCoordinatorByPhone
* @property {(phoneNumber: string) => string|null} findProjectByCoordinatorPhone
* @property {(projectName: string) => Coordinator|null} findCoordinatorByProject
* @property {() => Member[]} getMembers
* @property {(member: Member) => void} saveMember
* @property {(phoneNumber: string) => Member|null} findMemberByPhone
Expand Down Expand Up @@ -106,6 +108,14 @@ async function dbPlugin(fastify, { dbFolder }) {
writeDb(data)
},

deleteCoordinatorByPhone(phoneNumber) {
const data = readDb()
data.coordinators = data.coordinators.filter(
(c) => c.phoneNumber !== phoneNumber,
)
writeDb(data)
},

findCoordinatorByPhone(phoneNumber) {
const coordinator = readDb().coordinators.find(
(c) => c.phoneNumber === phoneNumber,
Expand All @@ -120,6 +130,13 @@ async function dbPlugin(fastify, { dbFolder }) {
return coordinator ? coordinator.projectName : null
},

findCoordinatorByProject(projectName) {
const coordinator = readDb().coordinators.find(
(c) => c.projectName === projectName,
)
return coordinator || null
},

getMembers() {
return readDb().members
},
Expand Down
4 changes: 4 additions & 0 deletions src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export const tooManyProjects = () =>
export const projectNotFoundError = () =>
new HttpError(404, 'PROJECT_NOT_FOUND', 'Project not found')

/** @param {string} message */
export const notFoundError = (message) =>
new HttpError(404, 'NOT_FOUND', message)

/** @param {never} value */
export const shouldBeImpossibleError = (value) =>
new Error(`${value} should be impossible`)
Expand Down
56 changes: 55 additions & 1 deletion src/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,19 @@ export default async function authRoutes(fastify, opts) {

// Check if coordinator already exists
const existingCoordinator = fastify.db.findCoordinatorByPhone(phoneNumber)
if (existingCoordinator) {
if (existingCoordinator?.token) {
fastify.log.warn(`Coordinator already exists for phone: ${phoneNumber}`)
throw errors.conflictError('Phone number already registered')
}

// Check if project name already exists
const existingProjectCoordinator =
fastify.db.findCoordinatorByProject(projectName)
if (existingProjectCoordinator) {
fastify.log.warn(`Project name already exists: ${projectName}`)
throw errors.conflictError('Project name already exists')
}

const projects = await fastify.comapeo.listProjects()
const existingProject = projects.find((p) => p.name === projectName)
if (existingProject) {
Expand All @@ -91,6 +98,53 @@ export default async function authRoutes(fastify, opts) {
}
},
)
// DELETE /auth/unregister
fastify.delete(
'/auth/unregister',
{
schema: {
body: Type.Object({
phoneNumber: Type.String(),
}),
response: {
200: Type.Object({
data: Type.Object({
message: Type.String(),
}),
}),
'4xx': schemas.errorResponse,
},
},
async preHandler(req) {
verifyBearerAuth(req, serverBearerToken)
},
},
async (req) => {
const { phoneNumber } =
/** @type {import('fastify').FastifyRequest<{Body: {phoneNumber: string}}>} */ (
req
).body

fastify.log.info(`Attempting to unregister coordinator: ${phoneNumber}`)

// Check if coordinator exists
const coordinator = fastify.db.findCoordinatorByPhone(phoneNumber)
if (!coordinator) {
fastify.log.warn(`No coordinator found for phone: ${phoneNumber}`)
throw errors.notFoundError('Coordinator not found')
}

// Delete coordinator
fastify.db.deleteCoordinatorByPhone(phoneNumber)
fastify.log.info(`Successfully unregistered coordinator: ${phoneNumber}`)

return {
data: {
message: 'Coordinator successfully unregistered',
},
}
},
)
// POST /auth/coordinator
fastify.post(
'/auth/coordinator',
Expand Down
73 changes: 68 additions & 5 deletions test/test_auth_script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,39 @@ echo "🧪 Starting AUTH API Tests..."
echo "========================"
echo

# Test POST /auth/register with existing number (should fail)
echo "POST /auth/register with existing number"
# Test POST /auth/register with new random number
echo "POST /auth/register with new number"
echo "----------------------------------------"
RESPONSE=$(curl -s -f -X POST \
"${HOST}/auth/register" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BEARER_TOKEN}" \
-d '{
"phoneNumber": "'"${RANDOM_PHONE}"'",
"projectName": "'"${PROJECT_NAME} 1"'"
}')
echo "Response: ${RESPONSE}"
echo "✅ Passed"
echo

# Test POST /auth/register with same random number
echo "POST /auth/register with same number"
echo "----------------------------------------"
RESPONSE=$(curl -s -f -X POST \
"${HOST}/auth/register" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BEARER_TOKEN}" \
-d '{
"phoneNumber": "'"${RANDOM_PHONE}"'",
"projectName": "'"${PROJECT_NAME}"'"
}')
echo "Response: ${RESPONSE}"
echo "✅ Passed"
echo


# Test POST /auth/register with existing project name (should fail)
echo "POST /auth/register with existing project name"
echo "----------------------------------------"
if curl -s -f -X POST \
"${HOST}/auth/register" \
Expand All @@ -45,8 +76,39 @@ else
fi
echo

# Test POST /auth/register with new random number
echo "POST /auth/register with new number"
# Test DELETE /auth/unregister with invalid phone number
echo "DELETE /auth/unregister with invalid phone"
echo "----------------------------------------"
if curl -s -f -X DELETE \
"${HOST}/auth/unregister" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BEARER_TOKEN}" \
-d '{
"phoneNumber": "+999999999"
}' 2>/dev/null; then
echo "❌ Failed: Request should have failed for non-existent number"
exit 1
else
echo "✅ Passed: Request failed as expected for non-existent number"
fi
echo

# Test DELETE /auth/unregister with valid phone number
echo "DELETE /auth/unregister with valid phone"
echo "----------------------------------------"
RESPONSE=$(curl -s -f -X DELETE \
"${HOST}/auth/unregister" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${BEARER_TOKEN}" \
-d '{
"phoneNumber": "'"${RANDOM_PHONE}"'"
}')
echo "Response: ${RESPONSE}"
echo "✅ Passed"
echo

# Verify coordinator was deleted by trying to register with same number again
echo "POST /auth/register to verify coordinator was deleted"
echo "----------------------------------------"
RESPONSE=$(curl -s -f -X POST \
"${HOST}/auth/register" \
Expand All @@ -57,7 +119,7 @@ RESPONSE=$(curl -s -f -X POST \
"projectName": "'"${PROJECT_NAME}"'"
}')
echo "Response: ${RESPONSE}"
echo "✅ Passed"
echo "✅ Passed: Successfully re-registered deleted coordinator"
echo

# Create project for the registered coordinator
Expand Down Expand Up @@ -94,6 +156,7 @@ if ! echo "${RESPONSE}" | jq -e ".data[] | select(.name == \"${PROJECT_NAME}\")"
fi
echo "✅ Passed: Project exists"
echo

# Test POST /auth/coordinator with new number
echo "POST /auth/coordinator"
echo "------------------------------------------"
Expand Down

0 comments on commit 014b9c5

Please sign in to comment.