Showing
19 changed files
with
675 additions
and
0 deletions
api/config.go
0 → 100644
1 | +package main | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "io/ioutil" | ||
6 | +) | ||
7 | + | ||
8 | +type Config struct { | ||
9 | + Server ConfigServer `json:"server"` | ||
10 | + Database ConfigDatabase `json:"database"` | ||
11 | +} | ||
12 | + | ||
13 | +type ConfigServer struct { | ||
14 | + LocalMode bool `json:"local_mode"` | ||
15 | + Port int `json:"port"` | ||
16 | +} | ||
17 | + | ||
18 | +type ConfigDatabase struct { | ||
19 | + Host string `json:"host"` | ||
20 | + Port int `json:"port"` | ||
21 | + User string `json:"user"` | ||
22 | + Password string `json:"password"` | ||
23 | + Schema string `json:"schema"` | ||
24 | +} | ||
25 | + | ||
26 | +func LoadConfig(filePath string) (*Config, error) { | ||
27 | + cfg := &Config{} | ||
28 | + | ||
29 | + dataBytes, err := ioutil.ReadFile(filePath) | ||
30 | + if err != nil { | ||
31 | + return cfg, err | ||
32 | + } | ||
33 | + | ||
34 | + json.Unmarshal(dataBytes, cfg) | ||
35 | + | ||
36 | + return cfg, nil | ||
37 | +} |
api/endpoints/cell.go
0 → 100644
1 | +package endpoints | ||
2 | + | ||
3 | +import ( | ||
4 | + "classroom/functions" | ||
5 | + "classroom/models" | ||
6 | + "database/sql" | ||
7 | + "fmt" | ||
8 | + "net/http" | ||
9 | + "strconv" | ||
10 | + "strings" | ||
11 | + | ||
12 | + "github.com/julienschmidt/httprouter" | ||
13 | +) | ||
14 | + | ||
15 | +// GET /timetables/<file_id>/<sheet_id>/cell | ||
16 | +func (e *Endpoints) CellGet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | ||
17 | + // Get user email | ||
18 | + var email string | ||
19 | + if _email, ok := r.Header["X-User-Email"]; ok { | ||
20 | + email = _email[0] | ||
21 | + } else { | ||
22 | + functions.ResponseError(w, 401, "X-User-Email 헤더를 보내세요.") | ||
23 | + return | ||
24 | + } | ||
25 | + | ||
26 | + // Get Path Parameters | ||
27 | + fileID := ps.ByName("file_id") | ||
28 | + sheetID := ps.ByName("sheet_id") | ||
29 | + | ||
30 | + // Get Query Parameters | ||
31 | + qp := r.URL.Query() | ||
32 | + var cellColumn string | ||
33 | + var cellStart int | ||
34 | + var cellEnd int | ||
35 | + var err error | ||
36 | + | ||
37 | + if _cellColumn, ok := qp["column"]; ok { | ||
38 | + cellColumn = strings.ToUpper(_cellColumn[0]) | ||
39 | + } else { | ||
40 | + functions.ResponseError(w, 400, "column 파라미터를 보내세요.") | ||
41 | + return | ||
42 | + } | ||
43 | + | ||
44 | + if _cellStart, ok := qp["start"]; ok { | ||
45 | + cellStart, err = strconv.Atoi(_cellStart[0]) | ||
46 | + if err != nil { | ||
47 | + functions.ResponseError(w, 400, "start 파라미터를 보내세요.") | ||
48 | + return | ||
49 | + } | ||
50 | + } | ||
51 | + if _cellEnd, ok := qp["end"]; ok { | ||
52 | + cellEnd, err = strconv.Atoi(_cellEnd[0]) | ||
53 | + if err != nil { | ||
54 | + functions.ResponseError(w, 400, "end 파라미터를 보내세요.") | ||
55 | + return | ||
56 | + } | ||
57 | + } | ||
58 | + | ||
59 | + // Check Permission | ||
60 | + var _timetable, _email string | ||
61 | + timetable := fmt.Sprintf("%s,%s", fileID, sheetID) | ||
62 | + row := e.DB.QueryRow(` | ||
63 | + SELECT a.timetable_id, u.email | ||
64 | + FROM allowlist AS a, users AS u | ||
65 | + WHERE a.timetable_id=? | ||
66 | + AND a.user_id=u.id; | ||
67 | + `, timetable) | ||
68 | + if err := row.Scan(&_timetable, &_email); err != nil { | ||
69 | + if err == sql.ErrNoRows { | ||
70 | + functions.ResponseError(w, 404, "존재하지 않은 timetable.") | ||
71 | + return | ||
72 | + } | ||
73 | + } | ||
74 | + if _email != email { | ||
75 | + functions.ResponseError(w, 403, "timetable 접근 권한 부족") | ||
76 | + return | ||
77 | + } | ||
78 | + | ||
79 | + // Result Resp | ||
80 | + resp := models.CellGetResponse{} | ||
81 | + resp.Cells = []models.CellItem{} | ||
82 | + | ||
83 | + // Querying | ||
84 | + rows, err := e.DB.Query(` | ||
85 | + SELECT u.email, u.id, t.cell_column, t.cell_start, t.cell_end, t.lecture, t.professor, t.transaction_id, t.created_at, t.capacity | ||
86 | + FROM transactions AS t, users AS u | ||
87 | + WHERE t.user_id=u.id | ||
88 | + AND u.email=? | ||
89 | + AND t.transaction_type=1 | ||
90 | + AND t.timetable_id=? | ||
91 | + AND t.cell_column=?;`, email, timetable, cellColumn) | ||
92 | + if err != nil { | ||
93 | + if err == sql.ErrNoRows { | ||
94 | + resp.CellsCount = 0 | ||
95 | + functions.ResponseOK(w, "success", resp) | ||
96 | + return | ||
97 | + } | ||
98 | + functions.ResponseError(w, 500, err.Error()) | ||
99 | + return | ||
100 | + } | ||
101 | + defer rows.Close() | ||
102 | + | ||
103 | + cells := []models.CellTransactionModel{} | ||
104 | + for rows.Next() { | ||
105 | + temp := models.CellTransactionModel{} | ||
106 | + err := rows.Scan(&temp.UserEmail, &temp.UserID, &temp.CellColumn, &temp.CellStart, &temp.CellEnd, &temp.Lecture, &temp.Professor, &temp.TransactionID, &temp.CreatedAt, &temp.Capacity) | ||
107 | + if err != nil { | ||
108 | + continue | ||
109 | + } | ||
110 | + cells = append(cells, temp) | ||
111 | + } | ||
112 | + | ||
113 | + // Compare | ||
114 | + for i := cellStart; i <= cellEnd; i++ { | ||
115 | + isInRange := false | ||
116 | + for _, cell := range cells { | ||
117 | + if functions.InRange(i, cell.CellStart, cell.CellEnd) { | ||
118 | + temp := models.CellItem{} | ||
119 | + temp.Cell = fmt.Sprintf("%s%d", cellColumn, i) | ||
120 | + temp.IsReserved = true | ||
121 | + temp.UserEmail = cell.UserEmail | ||
122 | + temp.UserID = cell.UserID | ||
123 | + temp.Lecture = cell.Lecture | ||
124 | + temp.Professor = cell.Professor | ||
125 | + temp.TransactionID = cell.TransactionID | ||
126 | + temp.CreatedAt = functions.ToKST(cell.CreatedAt) | ||
127 | + temp.Capacity = cell.Capacity | ||
128 | + | ||
129 | + resp.Cells = append(resp.Cells, temp) | ||
130 | + isInRange = true | ||
131 | + break | ||
132 | + } | ||
133 | + } | ||
134 | + | ||
135 | + if !isInRange { | ||
136 | + temp := models.CellItem{} | ||
137 | + temp.Cell = fmt.Sprintf("%s%d", cellColumn, i) | ||
138 | + temp.IsReserved = false | ||
139 | + | ||
140 | + resp.Cells = append(resp.Cells, temp) | ||
141 | + } | ||
142 | + } | ||
143 | + | ||
144 | + // Struct for response | ||
145 | + resp.CellsCount = len(resp.Cells) | ||
146 | + | ||
147 | + functions.ResponseOK(w, "success", resp) | ||
148 | +} |
api/endpoints/endpoints.go
0 → 100644
api/endpoints/go.mod
0 → 100644
api/endpoints/go.sum
0 → 100644
api/endpoints/index.go
0 → 100644
1 | +package endpoints | ||
2 | + | ||
3 | +import ( | ||
4 | + "classroom/functions" | ||
5 | + "classroom/models" | ||
6 | + "net/http" | ||
7 | + | ||
8 | + "github.com/julienschmidt/httprouter" | ||
9 | +) | ||
10 | + | ||
11 | +// GET / | ||
12 | +func (e *Endpoints) IndexGet(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { | ||
13 | + w.Header().Set("Content-Type", "application/json") | ||
14 | + | ||
15 | + // Struct for response | ||
16 | + resp := models.IndexResponse{} | ||
17 | + resp.WelcomeMessage = "Hello, Kyung Hee!" | ||
18 | + | ||
19 | + // Response with JSON | ||
20 | + functions.ResponseOK(w, "success", resp) | ||
21 | +} |
api/endpoints/reservation.go
0 → 100644
1 | +package endpoints | ||
2 | + | ||
3 | +import ( | ||
4 | + "classroom/functions" | ||
5 | + "classroom/models" | ||
6 | + "database/sql" | ||
7 | + "encoding/json" | ||
8 | + "fmt" | ||
9 | + "io/ioutil" | ||
10 | + "net/http" | ||
11 | + "strings" | ||
12 | + | ||
13 | + "github.com/julienschmidt/httprouter" | ||
14 | +) | ||
15 | + | ||
16 | +// POST /timetables/<file_id>/<sheet_id>/reservation | ||
17 | +func (e *Endpoints) ReservationPost(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | ||
18 | + // Get user email | ||
19 | + var email string | ||
20 | + if _email, ok := r.Header["X-User-Email"]; ok { | ||
21 | + email = _email[0] | ||
22 | + } else { | ||
23 | + functions.ResponseError(w, 401, "X-User-Email 헤더를 보내세요.") | ||
24 | + return | ||
25 | + } | ||
26 | + | ||
27 | + // Get Path Parameters | ||
28 | + fileID := ps.ByName("file_id") | ||
29 | + sheetID := ps.ByName("sheet_id") | ||
30 | + | ||
31 | + // Check Permission | ||
32 | + var _timetable, _email string | ||
33 | + var userID int | ||
34 | + timetable := fmt.Sprintf("%s,%s", fileID, sheetID) | ||
35 | + row := e.DB.QueryRow(` | ||
36 | + SELECT a.timetable_id, u.email, u.id | ||
37 | + FROM allowlist AS a, users AS u | ||
38 | + WHERE a.timetable_id=? | ||
39 | + AND a.user_id=u.id; | ||
40 | + `, timetable) | ||
41 | + if err := row.Scan(&_timetable, &_email, &userID); err != nil { | ||
42 | + if err == sql.ErrNoRows { | ||
43 | + functions.ResponseError(w, 404, "존재하지 않는 timetable") | ||
44 | + return | ||
45 | + } | ||
46 | + functions.ResponseError(w, 500, "예기치 못한 에러 발생 : "+err.Error()) | ||
47 | + return | ||
48 | + } | ||
49 | + if _email != email { | ||
50 | + functions.ResponseError(w, 403, "timetable 접근 권한 부족") | ||
51 | + return | ||
52 | + } | ||
53 | + | ||
54 | + // Parse Request Data | ||
55 | + type reqDataStruct struct { | ||
56 | + Column *string `json:"column"` | ||
57 | + Start *int `json:"start"` | ||
58 | + End *int `json:"end"` | ||
59 | + Lecture *string `json:"lecture"` | ||
60 | + Professor *string `json:"professor"` | ||
61 | + Capacity *int `json:"capacity"` | ||
62 | + } | ||
63 | + var reqData reqDataStruct | ||
64 | + if strings.Contains(r.Header.Get("Content-Type"), "application/json") { | ||
65 | + body, err := ioutil.ReadAll(r.Body) | ||
66 | + if err != nil { | ||
67 | + functions.ResponseError(w, 500, err.Error()) | ||
68 | + } | ||
69 | + json.Unmarshal(body, &reqData) | ||
70 | + } else { | ||
71 | + functions.ResponseError(w, 400, "JSON 형식만 가능합니다.") | ||
72 | + return | ||
73 | + } | ||
74 | + if reqData.Column == nil || reqData.Start == nil || reqData.End == nil || | ||
75 | + reqData.Lecture == nil || reqData.Professor == nil || reqData.Capacity == nil { | ||
76 | + functions.ResponseError(w, 400, "파라미터를 전부 보내주세요.") | ||
77 | + return | ||
78 | + } | ||
79 | + | ||
80 | + // Querying (Cell Validation Check) | ||
81 | + isPossible := true | ||
82 | + rows, err := e.DB.Query(` | ||
83 | + SELECT cell_start, cell_end | ||
84 | + FROM transactions | ||
85 | + WHERE transaction_type=1 | ||
86 | + AND cell_column=?; | ||
87 | + `, *(reqData.Column)) | ||
88 | + if err == sql.ErrNoRows { | ||
89 | + isPossible = true | ||
90 | + } | ||
91 | + defer rows.Close() | ||
92 | + | ||
93 | +loopCheckingValidation: | ||
94 | + for rows.Next() { | ||
95 | + var _start, _end int | ||
96 | + err = rows.Scan(&_start, &_end) | ||
97 | + if err != nil { | ||
98 | + continue | ||
99 | + } | ||
100 | + for i := *(reqData.Start); i <= *(reqData.End); i++ { | ||
101 | + if functions.InRange(i, _start, _end) { | ||
102 | + isPossible = false | ||
103 | + break loopCheckingValidation | ||
104 | + } | ||
105 | + } | ||
106 | + } | ||
107 | + | ||
108 | + if !isPossible { | ||
109 | + functions.ResponseError(w, 500, "해당 셀 범위에 예약이 존재합니다.") | ||
110 | + return | ||
111 | + } | ||
112 | + | ||
113 | + // Result Resp | ||
114 | + resp := models.ReservationPostResponse{} | ||
115 | + | ||
116 | + // Querying (Making a Transaction) | ||
117 | + res, err := e.DB.Exec(` | ||
118 | + INSERT INTO transactions (transaction_type, user_id, timetable_id, lecture, capacity, cell_column, cell_start, cell_end, professor) | ||
119 | + VALUES (1, ?, ?, ?, ?, ?, ?, ?, ?); | ||
120 | + `, userID, timetable, *(reqData.Lecture), *(reqData.Capacity), *(reqData.Column), *(reqData.Start), *(reqData.End), *(reqData.Professor)) | ||
121 | + if err != nil { | ||
122 | + functions.ResponseError(w, 500, err.Error()) | ||
123 | + return | ||
124 | + } | ||
125 | + | ||
126 | + resp.TransactionID, err = res.LastInsertId() | ||
127 | + if err != nil { | ||
128 | + functions.ResponseError(w, 500, err.Error()) | ||
129 | + return | ||
130 | + } | ||
131 | + | ||
132 | + resp.IsSuccess = true | ||
133 | + resp.CellColumn = *(reqData.Column) | ||
134 | + resp.CellStart = *(reqData.Start) | ||
135 | + resp.CellEnd = *(reqData.End) | ||
136 | + resp.Lecture = *(reqData.Lecture) | ||
137 | + resp.Professor = *(reqData.Professor) | ||
138 | + | ||
139 | + functions.ResponseOK(w, "success", resp) | ||
140 | +} | ||
141 | + | ||
142 | +// DELETE /timetables/<file_id>/<sheet_id>/reservation/<reservation_id> | ||
143 | +func (e *Endpoints) ReservationDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { | ||
144 | + // Get user email | ||
145 | + var email string | ||
146 | + if _email, ok := r.Header["X-User-Email"]; ok { | ||
147 | + email = _email[0] | ||
148 | + } else { | ||
149 | + functions.ResponseError(w, 401, "X-User-Email 헤더를 보내세요.") | ||
150 | + return | ||
151 | + } | ||
152 | + | ||
153 | + // Get Path Parameters | ||
154 | + fileID := ps.ByName("file_id") | ||
155 | + sheetID := ps.ByName("sheet_id") | ||
156 | + reservationID := ps.ByName("reservation_id") | ||
157 | + | ||
158 | + // Check Timetable Permission | ||
159 | + var _timetable, _email string | ||
160 | + var userID int | ||
161 | + timetable := fmt.Sprintf("%s,%s", fileID, sheetID) | ||
162 | + row := e.DB.QueryRow(` | ||
163 | + SELECT a.timetable_id, u.email, u.id | ||
164 | + FROM allowlist AS a, users AS u | ||
165 | + WHERE a.timetable_id=? | ||
166 | + AND a.user_id=u.id; | ||
167 | + `, timetable) | ||
168 | + if err := row.Scan(&_timetable, &_email, &userID); err != nil { | ||
169 | + if err == sql.ErrNoRows { | ||
170 | + functions.ResponseError(w, 404, "존재하지 않는 timetable") | ||
171 | + return | ||
172 | + } | ||
173 | + functions.ResponseError(w, 500, "예기치 못한 에러 발생 : "+err.Error()) | ||
174 | + return | ||
175 | + } | ||
176 | + if _email != email { | ||
177 | + functions.ResponseError(w, 403, "timetable 접근 권한 부족") | ||
178 | + return | ||
179 | + } | ||
180 | + | ||
181 | + // Check Transaction Permission | ||
182 | + var _transactionType int64 | ||
183 | + row = e.DB.QueryRow(` | ||
184 | + SELECT u.email, t.transaction_type | ||
185 | + FROM transactions AS t, users AS u | ||
186 | + WHERE t.user_id=u.id | ||
187 | + AND t.transaction_id=?; | ||
188 | + `, reservationID) | ||
189 | + err := row.Scan(&_email, &_transactionType) | ||
190 | + if err != nil { | ||
191 | + if err == sql.ErrNoRows { | ||
192 | + functions.ResponseError(w, 404, "존재하지 않는 예약") | ||
193 | + return | ||
194 | + } | ||
195 | + functions.ResponseError(w, 500, "예기치 못한 에러 발생 : "+err.Error()) | ||
196 | + return | ||
197 | + } | ||
198 | + if _email != email { | ||
199 | + functions.ResponseError(w, 403, "예약 접근 권한 부족") | ||
200 | + return | ||
201 | + } | ||
202 | + if _transactionType == 0 { | ||
203 | + functions.ResponseError(w, 500, "이미 취소된 예약") | ||
204 | + return | ||
205 | + } | ||
206 | + | ||
207 | + // Querying | ||
208 | + res, err := e.DB.Exec(` | ||
209 | + UPDATE transactions SET transaction_type=0 WHERE transaction_id=? | ||
210 | + `, reservationID) | ||
211 | + if err != nil { | ||
212 | + functions.ResponseError(w, 500, err.Error()) | ||
213 | + return | ||
214 | + } | ||
215 | + if affected, _ := res.RowsAffected(); affected != 1 { | ||
216 | + functions.ResponseError(w, 500, "예기치 못한 에러 발생. (RowsAffected != 1)") | ||
217 | + return | ||
218 | + } | ||
219 | + | ||
220 | + functions.ResponseOK(w, "success", nil) | ||
221 | +} |
api/functions/compare.go
0 → 100644
api/functions/go.mod
0 → 100644
api/functions/response.go
0 → 100644
1 | +package functions | ||
2 | + | ||
3 | +import ( | ||
4 | + "encoding/json" | ||
5 | + "log" | ||
6 | + "net/http" | ||
7 | + | ||
8 | + "classroom/models" | ||
9 | +) | ||
10 | + | ||
11 | +// ResponseOK make 200 response. | ||
12 | +func ResponseOK(w http.ResponseWriter, msg string, data interface{}) { | ||
13 | + w.Header().Set("Content-Type", "application/json") | ||
14 | + w.Header().Set("Access-Control-Allow-Origin", "*") | ||
15 | + w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | ||
16 | + w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") | ||
17 | + w.WriteHeader(200) | ||
18 | + json.NewEncoder(w).Encode(&models.Response{ | ||
19 | + Status: 200, | ||
20 | + Message: msg, | ||
21 | + Data: data, | ||
22 | + }) | ||
23 | +} | ||
24 | + | ||
25 | +// ResponseError make error response. | ||
26 | +func ResponseError(w http.ResponseWriter, errorCode int, errorMsg string) { | ||
27 | + log.Println("[Error] :", errorCode, errorMsg) | ||
28 | + | ||
29 | + w.Header().Set("Content-Type", "application/json") | ||
30 | + w.Header().Set("Access-Control-Allow-Origin", "*") | ||
31 | + w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") | ||
32 | + w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") | ||
33 | + w.WriteHeader(errorCode) | ||
34 | + json.NewEncoder(w).Encode(&models.Response{ | ||
35 | + Status: errorCode, | ||
36 | + Message: errorMsg, | ||
37 | + Data: nil, | ||
38 | + }) | ||
39 | +} |
api/functions/time.go
0 → 100644
api/go.mod
0 → 100644
1 | +module classroom | ||
2 | + | ||
3 | +go 1.14 | ||
4 | + | ||
5 | +require ( | ||
6 | + github.com/go-sql-driver/mysql v1.5.0 | ||
7 | + github.com/julienschmidt/httprouter v1.3.0 | ||
8 | + github.com/rs/cors v1.7.0 | ||
9 | + | ||
10 | + classroom/endpoints v0.0.0 | ||
11 | + classroom/models v0.0.0 | ||
12 | + classroom/functions v0.0.0 | ||
13 | +) | ||
14 | + | ||
15 | +replace ( | ||
16 | + classroom/endpoints v0.0.0 => ./endpoints | ||
17 | + classroom/models v0.0.0 => ./models | ||
18 | + classroom/functions v0.0.0 => ./functions | ||
19 | +) | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
api/go.sum
0 → 100644
1 | +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= | ||
2 | +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= | ||
3 | +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= | ||
4 | +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= | ||
5 | +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= | ||
6 | +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= |
api/main.go
0 → 100644
1 | +package main | ||
2 | + | ||
3 | +import ( | ||
4 | + "database/sql" | ||
5 | + "fmt" | ||
6 | + "log" | ||
7 | + "net/http" | ||
8 | + "os" | ||
9 | + "strconv" | ||
10 | + "time" | ||
11 | + | ||
12 | + "classroom/endpoints" | ||
13 | + "classroom/functions" | ||
14 | + | ||
15 | + _ "github.com/go-sql-driver/mysql" | ||
16 | + "github.com/julienschmidt/httprouter" | ||
17 | + "github.com/rs/cors" | ||
18 | +) | ||
19 | + | ||
20 | +var logger *log.Logger | ||
21 | + | ||
22 | +type HostSwitch map[string]http.Handler | ||
23 | + | ||
24 | +func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
25 | + if handler := hs[r.Host]; handler != nil { | ||
26 | + ip := r.RemoteAddr | ||
27 | + log.Println("[Req]", r.Method, r.URL, ip) | ||
28 | + handler.ServeHTTP(w, r) | ||
29 | + } else { | ||
30 | + functions.ResponseError(w, 403, "Forbidden hostname : "+r.Host) | ||
31 | + } | ||
32 | +} | ||
33 | + | ||
34 | +func main() { | ||
35 | + // Logger | ||
36 | + logger = log.New(os.Stdout, "LOG ", log.LstdFlags) | ||
37 | + | ||
38 | + // Config | ||
39 | + cfg, err := LoadConfig("config.json") | ||
40 | + if err != nil { | ||
41 | + log.Fatal(err) | ||
42 | + } | ||
43 | + | ||
44 | + // DB Setting | ||
45 | + if !(cfg.Server.LocalMode) { | ||
46 | + time.Sleep(time.Second * 10) | ||
47 | + } | ||
48 | + dbStr := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?allowNativePasswords=true&parseTime=true", | ||
49 | + cfg.Database.User, | ||
50 | + cfg.Database.Password, | ||
51 | + cfg.Database.Host, | ||
52 | + cfg.Database.Port, | ||
53 | + cfg.Database.Schema) | ||
54 | + db, err := sql.Open("mysql", dbStr) | ||
55 | + if err != nil { | ||
56 | + log.Fatal(err) | ||
57 | + } | ||
58 | + defer db.Close() | ||
59 | + ep := endpoints.Endpoints{DB: db} | ||
60 | + | ||
61 | + // Router Setting | ||
62 | + router := httprouter.New() | ||
63 | + router.GET("/api", ep.IndexGet) | ||
64 | + router.GET("/api/timetables/:file_id/:sheet_id/cell", ep.CellGet) | ||
65 | + router.POST("/api/timetables/:file_id/:sheet_id/reservation", ep.ReservationPost) | ||
66 | + router.DELETE("/api/timetables/:file_id/:sheet_id/reservation/:reservation_id", ep.ReservationDelete) | ||
67 | + | ||
68 | + // Local Mode | ||
69 | + portStr := strconv.Itoa(cfg.Server.Port) | ||
70 | + if cfg.Server.LocalMode { | ||
71 | + handler := cors.AllowAll().Handler(router) | ||
72 | + | ||
73 | + // Start Server in Local Mode | ||
74 | + log.Println("[Local Mode] Starting HTTP API Server on port", portStr) | ||
75 | + log.Fatal(http.ListenAndServe(":"+portStr, handler)) | ||
76 | + | ||
77 | + } else { // Release Mode | ||
78 | + handler := cors.AllowAll().Handler(router) | ||
79 | + hs := make(HostSwitch) | ||
80 | + hs["web-api"] = handler | ||
81 | + | ||
82 | + // Start Server | ||
83 | + log.Println("[Release Mode] Starting HTTP API Server on port", portStr) | ||
84 | + log.Fatal(http.ListenAndServe(":"+portStr, hs)) | ||
85 | + } | ||
86 | +} |
api/models/cell.go
0 → 100644
1 | +package models | ||
2 | + | ||
3 | +type CellTransactionModel struct { | ||
4 | + TransactionID int | ||
5 | + UserID int | ||
6 | + UserEmail string | ||
7 | + Lecture string | ||
8 | + CellColumn string | ||
9 | + CellStart int | ||
10 | + CellEnd int | ||
11 | + Professor string | ||
12 | + CreatedAt string | ||
13 | + Capacity int | ||
14 | +} | ||
15 | + | ||
16 | +type CellGetResponse struct { | ||
17 | + Cells []CellItem `json:"cells"` | ||
18 | + CellsCount int `json:"cells_count"` | ||
19 | +} | ||
20 | + | ||
21 | +type CellItem struct { | ||
22 | + Cell string `json:"cell"` | ||
23 | + IsReserved bool `json:"is_reserved"` | ||
24 | + UserEmail string `json:"user_email"` | ||
25 | + UserID int `json:"user_id"` | ||
26 | + Lecture string `json:"lecture"` | ||
27 | + Professor string `json:"professor"` | ||
28 | + Capacity int `json:"capacity"` | ||
29 | + TransactionID int `json:"transaction_id"` | ||
30 | + CreatedAt string `json:"created_at"` | ||
31 | +} |
api/models/go.mod
0 → 100644
api/models/index.go
0 → 100644
api/models/reservation.go
0 → 100644
1 | +package models | ||
2 | + | ||
3 | +type ReservationPostResponse struct { | ||
4 | + IsSuccess bool `json:"is_success"` | ||
5 | + TransactionID int64 `json:"transaction_id"` | ||
6 | + CellColumn string `json:"cell_column"` | ||
7 | + CellStart int `json:"cell_start"` | ||
8 | + CellEnd int `json:"cell_end"` | ||
9 | + Lecture string `json:"lecture"` | ||
10 | + Professor string `json:"professor"` | ||
11 | +} |
-
Please register or login to post a comment