Skip to content

Commit

Permalink
目標が達成できたかどうかを返すresult APIを作成
Browse files Browse the repository at this point in the history
  • Loading branch information
MurakawaTakuya committed Dec 1, 2024
1 parent db72a9f commit 8ecea74
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 23 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,37 @@ API is provided by Firebase Cloud Functions. Database is provided by Firestore.
}
]
```

## Result
### Get Result
- URL: /result/:userId
- Empty userId will return all results
- Parameters
- limit: number (optional) - The maximum number of results to return.
- offset: number (optional) - The number of results to skip before starting to collect the result set.
- Method: GET
- Response
```
{
"successResults": [
{
"userId": "FZ5KQ4sv0wZCow0MdwniPbyeBvVv",
"goalId": "TFu8hBcwNLKt5boYluKZ",
"postId": "a0Y0YtgsCWJ1WJ6Ihpsh",
"goalText": "hello",
"postText": "",
"storedId": "http://localhost:9199/v0/b/todo-real-c28fa.firebasestorage.app/o/post%2Faed6999b-bf8c-4c7d-8bf6-447323ba25c4?alt=media&token=5cb7f8d0-e0bf-42ae-b0e1-3b84685f3ceb",
"deadline": "2023-11-30T15:51:00.000Z",
"submittedAt": "2025-12-01T12:46:18.000Z"
}
],
"failedPosts": [
{
"goalId": "LSVaBEI0KkfZnLDbztYc",
"userId": "FZ5KQ4sv0wZCow0MdwniPbyeBvVv",
"deadline": "2022-12-31T23:59:59.000Z",
"text": "数学の勉強する"
}
]
}
```
10 changes: 6 additions & 4 deletions functions/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ admin.initializeApp({
storageBucket: "todo-real-c28fa.appspot.com",
});

import goalRouter from "./routers/goalRouter";
import postRouter from "./routers/postRouter";
import resultRouter from "./routers/resultRouter";
import userRouer from "./routers/userRouter";

const app = express();
app.use(cors({ origin: true }));
app.use(helmet());
Expand All @@ -33,14 +38,11 @@ app.use(
})
);

import goalRouter from "./routers/goalRouter";
import postRouter from "./routers/postRouter";
import userRouer from "./routers/userRouter";
app.use("/user", userRouer);
app.use("/goal", goalRouter);
app.use("/post", postRouter);
app.use("/result", resultRouter);

// Cloud Functionsにデプロイする関数
const region = "asia-northeast1";

export const helloWorld = onRequest({ region: region }, (req, res) => {
Expand Down
7 changes: 1 addition & 6 deletions functions/src/routers/goalRouter.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import express, { Request, Response } from "express";
import admin from "firebase-admin";
import { Goal } from "./types";

const router = express.Router();
const db = admin.firestore();

interface Goal {
userId: string;
deadline: Date;
text: string;
}

// GET: 全ての目標を取得
router.get("/", async (req: Request, res: Response) => {
try {
Expand Down
9 changes: 1 addition & 8 deletions functions/src/routers/postRouter.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import express, { Request, Response } from "express";
import admin from "firebase-admin";
import { Post } from "./types";

const router = express.Router();
const db = admin.firestore();

interface Post {
userId: string;
storedId: string;
text: string;
goalId: string;
submittedAt: Date;
}

// GET: 全ての投稿を取得
router.get("/", async (req: Request, res: Response) => {
try {
Expand Down
115 changes: 115 additions & 0 deletions functions/src/routers/resultRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import express, { Request, Response } from "express";
import admin from "firebase-admin";
import { GoalWithId, SuccessResult } from "./types";

const router = express.Router();
const db = admin.firestore();

const getResults = async (limit: number, offset: number, userId?: string) => {
let goalQuery = db.collection("goal").limit(limit).offset(offset);
if (userId) {
goalQuery = goalQuery.where("userId", "==", userId);
}
const goalSnapshot = await goalQuery.get();

const goals = goalSnapshot.docs.map((doc) => {
const data = doc.data();
return {
goalId: doc.id,
userId: data.userId,
deadline: new Date(data.deadline._seconds * 1000),
text: data.text,
};
}) as GoalWithId[];

if (!goals || goals.length === 0) {
return { successResults: [], failedPosts: [] };
}

const postSnapshot = await db
.collection("post")
.where(
"goalId",
"in",
goals.map((goal) => goal.goalId)
)
.get();

const successResults: SuccessResult[] = [];
const failedPosts: GoalWithId[] = [];
goals.forEach((goal) => {
const post = postSnapshot.docs.find(
(doc) => doc.data().goalId === goal.goalId
);
if (post) {
const postData = post.data();
const submittedAt = postData.submittedAt.toDate();
if (submittedAt < goal.deadline) {
failedPosts.push(goal);
} else {
successResults.push({
userId: goal.userId,
goalId: goal.goalId,
postId: post.id,
goalText: goal.text,
postText: postData.text,
storedId: postData.storedId,
deadline: goal.deadline,
submittedAt: submittedAt,
});
}
} else {
failedPosts.push(goal);
}
});

return { successResults, failedPosts };
};

// GET: 全ての目標に対する結果を取得
router.get("/", async (req: Request, res: Response) => {
try {
const limit = req.query.limit ? Number(req.query.limit) : 10; // 取得数
const offset = req.query.offset ? Number(req.query.offset) : 0; // 開始位置
if (offset < 0) {
res.status(400).json({ message: "Offset must be a positive number" });
}
if (limit < 1) {
res.status(400).json({ message: "Limit must be more than zero" });
}

const results = await getResults(limit, offset);
res.json(results);
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
});

// GET: userIdから結果を取得
router.get("/:userId", async (req: Request, res: Response) => {
const userId = req.params.userId;

if (!userId) {
res.status(400).json({ message: "User ID is required" });
}

try {
const limit = req.query.limit ? Number(req.query.limit) : 10; // 取得数
const offset = req.query.offset ? Number(req.query.offset) : 0; // 開始位置
if (offset < 0) {
res.status(400).json({ message: "Offset must be a positive number" });
}
if (limit < 1) {
res.status(400).json({ message: "Limit must be more than zero" });
}

const results = await getResults(limit, offset, userId);
res.json(results);
} catch (error) {
console.error(error);
res.status(500).json({ message: "Internal server error" });
}
});

export default router;
33 changes: 33 additions & 0 deletions functions/src/routers/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export interface User {
name: string;
streak: number;
}

export interface Goal {
userId: string;
deadline: Date;
text: string;
}

export interface GoalWithId extends Goal {
goalId: string;
}

export interface Post {
userId: string;
storedId: string;
text: string;
goalId: string;
submittedAt: Date;
}

export interface SuccessResult {
userId: string;
goalId: string;
postId: string;
goalText: string;
postText: string;
storedId: string;
deadline: Date;
submittedAt: Date;
}
6 changes: 1 addition & 5 deletions functions/src/routers/userRouter.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import express, { Request, Response } from "express";
import admin from "firebase-admin";
import { User } from "./types";

const router = express.Router();
const db = admin.firestore();

interface User {
name: string;
streak: number;
}

// GET: 全てのユーザーデータを取得(アカウント機能を作成したら廃止)
router.get("/", async (req: Request, res: Response) => {
try {
Expand Down

0 comments on commit 8ecea74

Please sign in to comment.