OSDN Git Service

5dfa9039da8d7a63630c8d6d226ff9940cecad71
[webchat/WebChat.git] / profile.js
1 var config = require("./configure.js");\r
2 var resource = require("./resources.js");\r
3 var util = require("util");\r
4 var async = require("async");\r
5 var security = require("./security.js");\r
6 var ejs = require("ejs");\r
7 require("date-utils");\r
8 \r
9 var collection = new ProfileCollection();\r
10 \r
11 module.exports = function(app){\r
12         app.get("/profile",list_proc);\r
13         app.get("/profile/admin",admin_proc);\r
14         app.post("/profile/admin",admin_postproc);\r
15         app.get("/profile/detail",detail_proc);\r
16         app.post("/profile/detail",detail_postproc);\r
17         app.post("/profile/edit",edit_postproc); \r
18         app.get("/profile/registor",registor_proc); \r
19         app.post("/profile/registor",registor_postproc); \r
20 };\r
21 \r
22 function admin_proc(req, res)\r
23 {\r
24         var info = new security.SessionInfomation(true);\r
25         req.session.items = info;\r
26         async.waterfall([\r
27                 function(callback){\r
28                         PrepaerListAsync(req,callback);\r
29                 }\r
30         ],function(err,result){\r
31                 if(err != null)\r
32                         RenderMessage(res,err,info);\r
33                 else{\r
34                         result.token = req.session._csrf;\r
35                         res.setHeader("X-FRAME-OPTIONS","DENY");\r
36                         res.render("profile/admin",result);\r
37                 }\r
38         });\r
39 }\r
40 \r
41 function admin_postproc(req,res)\r
42 {\r
43         async.waterfall([\r
44                 function(cb){\r
45                         if(typeof(req.body.removeall) != "undefined")\r
46                                 collection.ClearAsync(cb);\r
47                         if(typeof(req.body.remove) != "undefined")\r
48                                 collection.RemoveRangeAsync(req.body.names,cb);\r
49                 }\r
50         ],function(err,result){\r
51                 if(err != null)\r
52                         RenderMessage(res,err,req.session.items);\r
53                 else\r
54                         RenderMessage(res,resource.success_remove,req.session.items);\r
55         });\r
56 }\r
57 \r
58 function list_proc(req, res)\r
59 {\r
60         if(typeof(req.session.items) != "undefined")\r
61                 req.session.items.admin = false;\r
62         async.waterfall([\r
63                 function(cb){\r
64                         PrepaerListAsync(req,cb);\r
65                 }\r
66         ],function(err,result){\r
67                 if(err != null)\r
68                         RenderMessage(res,err,req.session.items);\r
69                 else\r
70                         res.render("profile/list",result);\r
71         });\r
72 }\r
73 \r
74 function PrepaerListAsync(req,callback)\r
75 {\r
76         var limit = config.db_limit;\r
77         var start = 0;\r
78         var parttern = "";\r
79         if(typeof(req.query.start) != "undefined")\r
80                 start = parseInt(req.query.start);\r
81         if(typeof(req.query.limit) != "undefined")\r
82                 limit = parseInt(req.query.limit);\r
83 \r
84         async.waterfall([\r
85                 function(cb){\r
86                         if(typeof(req.query.search) != "undefined")\r
87                         {\r
88                                 parttern = req.query.search;\r
89                                 collection.FindByNameAsync(parttern,start,limit,cb);\r
90                         }else{\r
91                                 collection.ToArrayAsync(start,limit,cb);\r
92                         }\r
93                 }\r
94         ],function(err,result){\r
95                 if(err != null){\r
96                         callback(err,null);\r
97                 }else{\r
98                         var next = start + limit;\r
99                         var prev = start - limit;\r
100                         if(prev < 0)\r
101                                 prev = 0;\r
102                         for(var i = 0; i < result.length; i++)\r
103                                 result[i].lastmodified = result[i].lastmodified.toFormat("YYYY/MM/DD HH:MI:SS");\r
104                         callback(null,{list:result,search:parttern,next:next,prev:prev,limit:limit});\r
105                 }\r
106         });\r
107 }\r
108 \r
109 function detail_proc(req, res)\r
110 {\r
111         if(typeof(req.query.name) == "undefined")\r
112         {\r
113                 RenderMessage(res,resource.invaild_parameter,req.session.items);\r
114                 return;\r
115         }\r
116 \r
117         if(typeof(req.session.items) == "undefined")\r
118                 req.session.items = new security.SessionInfomation(false);\r
119 \r
120         async.waterfall([\r
121                 function(cb){\r
122                         collection.GetAsync(req.query.name,cb);\r
123                 },\r
124         ],function(err,result){\r
125                 if(err != null)\r
126                         RenderMessage(res,err,req.session.items);\r
127                 else if(result.length == 0)\r
128                         RenderMessage(res,resource.notfound_name,req.session.items);\r
129                 else{\r
130                         res.setHeader("X-FRAME-OPTIONS","DENY");\r
131                         res.render("profile/detail",{list:result,alias:config.alias,token:req.session._csrf,admin:req.session.items.admin});\r
132                 }\r
133         });\r
134 }\r
135 \r
136 function detail_postproc(req, res)\r
137 {\r
138         if(typeof(req.body.remove) != "undefined"){\r
139                 async.waterfall([\r
140                         function(cb){\r
141                                 if(typeof(req.session.items) != "undefined" && req.session.items.admin)\r
142                                         cb(null,true);\r
143                                 else\r
144                                         collection.AuthAsync(req.body.name,req.body.password,cb);\r
145                         },\r
146                         function(result,cb){\r
147                                 if(result)\r
148                                         collection.RemoveAsync(req.body.name,cb);\r
149                                 else\r
150                                         cb(null,null);\r
151                         }\r
152                 ],function(err,result){\r
153                         if(err != null)\r
154                                 RenderMessage(res,err,req.session.items);\r
155                         else if(result == null)\r
156                                 RenderMessage(res,resource.unmatch_password,req.session.items);\r
157                         else\r
158                                 RenderMessage(res,resource.success_remove,req.session.items);\r
159                 });\r
160         }else if(typeof(req.body.edit) != "undefined"){\r
161                 async.waterfall([\r
162                         function(cb){\r
163                                 if(typeof(req.session.items) != "undefined" && req.session.items.admin)\r
164                                         cb(null,true);\r
165                                 else\r
166                                         collection.AuthAsync(req.body.name,req.body.password,cb);\r
167                         },\r
168                         function(result,cb){\r
169                                 if(result)\r
170                                         collection.GetAsync(req.body.name,cb);\r
171                                 else\r
172                                         cb(null,null);\r
173                         }\r
174                 ],function(err,result){\r
175                         if(err != null){\r
176                                 RenderMessage(res,err,req.session.items);\r
177                         }else if(result != null){\r
178                                 res.setHeader("X-FRAME-OPTIONS","DENY");\r
179                                 res.render("profile/edit",{list:result,token:req.session._csrf,alias:config.alias});\r
180                         }else{\r
181                                 RenderMessage(res,resource.unmatch_password,req.session.items);\r
182                         }\r
183                 });\r
184         }else{\r
185                 RenderMessage(res,resource.invaild_parameter,req.session.items);\r
186         }\r
187 }\r
188 \r
189 function edit_postproc(req, res)\r
190 {\r
191         if(typeof(req.body.name) == "undefined")\r
192         {\r
193                 RenderMessage(res,resource.invaild_parameter,req.session.items);\r
194                 return;\r
195         }else if(typeof(req.body.edit) != "undefined"){\r
196                 var validator = new Validator();\r
197                 if(validator.Validate(req.body,config.alias))\r
198                 {\r
199                         RenderMessage(res,validator.Message,req.session.items);\r
200                         return;\r
201                 }\r
202                 async.waterfall([\r
203                         function(cb){\r
204                                 collection.UpdatAsync(req.body.name,req.body,cb);\r
205                         },\r
206                 ],function(err,result){\r
207                         if(err != null)\r
208                                 RenderMessage(res,err,req.session.items);\r
209                         else\r
210                                 RenderMessage(res,resource.success_edit,req.session.items);\r
211                 });\r
212         }else{\r
213                 RenderMessage(res,resource.invaild_parameter,req.session.items);\r
214         }\r
215 }\r
216 \r
217 function registor_postproc(req, res)\r
218 {\r
219         if(typeof(req.body.registor) != "undefined"){\r
220                 var validator = new Validator();\r
221                 if(validator.Validate(req.body,config.alias))\r
222                 {\r
223                         RenderMessage(res,validator.Message,req.session.items);\r
224                         return;\r
225                 }\r
226                 async.waterfall([\r
227                         function(cb){\r
228                                 collection.AddAsync(req.body,cb);\r
229                         }\r
230                 ],function(err,result){\r
231                         if(err != null)\r
232                                 RenderMessage(res,err,req.session.items);\r
233                         else\r
234                                 RenderMessage(res,resource.success_registor,req.session.items);\r
235                 });\r
236         }else{\r
237                 RenderMessage(resource.invaild_parameter,req.session.items);\r
238         }\r
239 }\r
240 \r
241 function registor_proc(req, res)\r
242 {\r
243         if(typeof(req.session.items) == "undefined")\r
244                 req.session.items = new security.SessionInfomation(false);\r
245 \r
246         res.setHeader("X-FRAME-OPTIONS","DENY");\r
247         res.render("profile/registor",{token:req.session._csrf,alias:config.alias});\r
248 }\r
249 \r
250 function RenderMessage(res,msg,info)\r
251 {\r
252         if(typeof(info) == "undefined" || typeof(info.admin) == "undefined")\r
253                 res.render("profile/message",{message:msg,admin:false});\r
254         else\r
255                 res.render("profile/message",{message:msg,admin:info.admin});\r
256 }\r
257 \r
258 //\r
259 // ProfileCollectionクラス\r
260 //\r
261 function ProfileCollection()\r
262 {\r
263         var MySQLPool = new require("./mysql_pool.js");\r
264         var murmurhash = require("murmurhash");\r
265         var pool = new MySQLPool({\r
266                                 host     : config.db_host,\r
267                                 user     : config.db_user,\r
268                                 password : config.db_password,\r
269                                 port     : config.db_port,\r
270                                 database : "webchat",\r
271                         });\r
272         this.AuthAsync = function(name,password,cb){\r
273                 async.waterfall([\r
274                         function(next){\r
275                                 pool.query("SELECT password FROM profilelist WHERE name_hash = ? and name = ?",[murmurhash.v3(name),name],next);\r
276                         },\r
277                         function(result,next){\r
278                                 if(result[0].password == md5_hex(password))\r
279                                         next(null,true);\r
280                                 else\r
281                                         next(null,false);\r
282                         }\r
283                 ],cb);\r
284         }\r
285         this.GetAsync = function(name,cb){\r
286                 pool.query("SELECT * FROM profilelist WHERE name_hash = ? and name = ?",[murmurhash.v3(name),name],cb);\r
287         }\r
288         this.AddAsync = function(data,cb){\r
289                 var item = GetItem(data);;\r
290                 pool.query("INSERT INTO profilelist SET ?",[item],cb);\r
291         }\r
292         this.UpdatAsync = function(name,data,cb){\r
293                 var item = GetItem(data);\r
294                 pool.query("UPDATE profilelist SET ? WHERE name = ?",[item,name],cb);\r
295         }\r
296         this.ClearAsync = function(cb){\r
297                 pool.query("TRUNCATE TABLE profilelist",null,cb);\r
298         }\r
299         this.RemoveRangeAsync = function(names,cb){\r
300                 pool.query("DELETE FROM profilelist WHERE name IN (?)",[names],cb);\r
301         }\r
302         this.RemoveAsync = function(name,cb){\r
303                 pool.query("DELETE FROM profilelist WHERE name_hash = ? and name = ?",[murmurhash.v3(name),name],cb);\r
304         }\r
305         this.FindByNameAsync = function(pattern,start,count,cb){\r
306                 pool.query("SELECT * FROM profilelist WHERE name LIKE ? LIMIT ?,?",[pattern+"%",start,count],cb);\r
307         }\r
308         this.ToArrayAsync = function(start,count,cb){\r
309                 pool.query("SELECT name,lastmodified FROM profilelist LIMIT ?,?",[start,count],cb);\r
310         }\r
311 \r
312         var crypto = require("crypto");\r
313         function md5_hex(src)\r
314         {\r
315                 var md5 = crypto.createHash('md5');\r
316                 md5.update(src, 'utf8');\r
317         return md5.digest('hex');\r
318         }\r
319 \r
320         function GetItem(data,newpw)\r
321         {\r
322                 var item = {\r
323                         name_hash:murmurhash.v3(data.name),\r
324                         lastmodified:new Date(),\r
325                 };\r
326                 for(var key in config.alias)\r
327                 {\r
328                         if(typeof(config.alias[key].nodefinetable) != "undefined" && \r
329                                 config.alias[key].nodefinetable)\r
330                                 continue;\r
331                         if(config.alias[key].visible_edit)\r
332                         {\r
333                                 if(config.alias[key].type == "password")\r
334                                         item[key] = md5_hex(data[key]);\r
335                                 else if(data[key] == "" && typeof(config.alias[key].defaultvalue) != "undefined")\r
336                                         item[key] = config.alias[key].defaultvalue;\r
337                                 else\r
338                                         item[key] = data[key];\r
339                         }\r
340                 }\r
341                 return item;\r
342         }\r
343 }\r
344 \r
345 //\r
346 // Validatorクラス\r
347 //\r
348 function Validator()\r
349 {\r
350         //\r
351         // バリテーションを行う。\r
352         // エラーがあった場合は真。そうでない場合は偽を返す\r
353         //\r
354         // @body バリテーションの対象となる連想配列\r
355         // @alias バリテーションを行う要素のリスト\r
356         this.Validate = function(body,alias){\r
357                 var result = false;\r
358                 this.Message = "";\r
359                 for(var key in alias)\r
360                 {\r
361                         if(alias[key].visible_edit == false)\r
362                                 continue;\r
363                         var message;\r
364                         if(typeof(alias[key].isnotempty) != "undefined" &&\r
365                                 alias[key].isnotempty && body[key] == "")\r
366                                         message = resource.is_not_empty;\r
367                         else if(typeof(alias[key].mustmatchitem) != "undefined" &&\r
368                                 body[key] != body[alias[key].mustmatchitem])\r
369                                         message = util.format(resource.must_match_item,alias[alias[key].mustmatchitem].name); \r
370                         else\r
371                                 message = IsValidate(body[key],alias[key].type,alias[key].rule);\r
372                         if(message != null)\r
373                         {\r
374                                 if(alias[key].name == "")\r
375                                         this.Message += "<p>" + message + "</p>\n";\r
376                                 else\r
377                                         this.Message += "<p>" + alias[key].name + ":" + message + "</p>\n";\r
378                                 result = true;\r
379                         }\r
380                 }\r
381                 return result;\r
382         }\r
383         // バリテーション時にエラーがあった場合、メッセージが記録される\r
384         this.Message = "";\r
385         function IsValidate(data,type,rule){\r
386                 if(typeof(data) == "undefined")\r
387                         throw "data is undefined";\r
388                 if(typeof(type) == "undefined")\r
389                         throw "type is undefined";\r
390 \r
391                 var result = null;\r
392 \r
393                 switch(type)\r
394                 {\r
395                         case "text":\r
396                         case "textarea":\r
397                         case "password":\r
398                                 if(typeof(data) != "string")\r
399                                         result = resource.is_not_string;\r
400                                 break;\r
401                         case "number":\r
402                                 if(data.match(/[^0-9]/g))\r
403                                         result = resource.is_not_number;\r
404                                 break;\r
405                         case "mail":\r
406                                 if(data != "" && !data.match(/^[A-Za-z0-9]+[\w\-\+]+@[\w\.-]+\.\w{2,}$/))\r
407                                         result = resource.is_not_mail;\r
408                                 break;\r
409                 }\r
410 \r
411                 if(typeof(rule) == "function")\r
412                         result = rule(data,type);\r
413 \r
414                 return result;\r
415         }\r
416 }\r