Commit 7703481083decab4059e94f13a8c3f6bb6dafd27

Authored by Apichat.Tum
1 parent cf86e9a3
Exists in master

fix REST API

app/controllers/home.controller.js
@@ -15,6 +15,17 @@ const lib = require('../lib') @@ -15,6 +15,17 @@ const lib = require('../lib')
15 const url = config.server.url 15 const url = config.server.url
16 const port = config.server.port 16 const port = config.server.port
17 17
  18 +function responseJSON(code, description, data, status) {
  19 + return {
  20 + "code": code,
  21 + "description": description,
  22 + "result": {
  23 + "data": data,
  24 + "status": status
  25 + }
  26 + }
  27 +}
  28 +
18 function strToTime(date) { 29 function strToTime(date) {
19 var strDate = new Date(date) 30 var strDate = new Date(date)
20 return strDate.getTime() 31 return strDate.getTime()
@@ -25,7 +36,7 @@ function ggToKendo(data) { @@ -25,7 +36,7 @@ function ggToKendo(data) {
25 try { 36 try {
26 for (var n = 0; n < data.items.length; n++) { 37 for (var n = 0; n < data.items.length; n++) {
27 dataToArr.push({ 38 dataToArr.push({
28 - "TaskID": data.items[n].etag, 39 + "TaskID": data.items[n].id,
29 "OwnerID": 2, 40 "OwnerID": 2,
30 "Title": data.items[n].summary, 41 "Title": data.items[n].summary,
31 "Description": data.items[n].description, 42 "Description": data.items[n].description,
@@ -51,22 +62,27 @@ function home(req, res) { @@ -51,22 +62,27 @@ function home(req, res) {
51 } 62 }
52 63
53 function index(req, res) { 64 function index(req, res) {
  65 + console.log(req.body)
54 lib.getNewToken((err, authUrl) => { 66 lib.getNewToken((err, authUrl) => {
55 if (err) { 67 if (err) {
56 - console.error(err.message) 68 + console.error(err)
57 } else { 69 } else {
  70 + console.info(authUrl)
58 res.send(authUrl) 71 res.send(authUrl)
59 } 72 }
60 }) 73 })
61 } 74 }
62 75
63 function setToken(req, res) { 76 function setToken(req, res) {
  77 + console.log(req.body)
64 var code = req.body.code 78 var code = req.body.code
65 lib.setNewToken(code, (err, token) => { 79 lib.setNewToken(code, (err, token) => {
66 if (err) { 80 if (err) {
  81 + console.error(err)
67 res.send(err) 82 res.send(err)
68 res.end() 83 res.end()
69 } else { 84 } else {
  85 + console.info(token)
70 res.send(token) 86 res.send(token)
71 res.end() 87 res.end()
72 } 88 }
@@ -74,28 +90,40 @@ function setToken(req, res) { @@ -74,28 +90,40 @@ function setToken(req, res) {
74 } 90 }
75 91
76 function events(req, res) { 92 function events(req, res) {
  93 + // console.log(req.body)
77 lib.authorize((err, auth, authUrl) => { 94 lib.authorize((err, auth, authUrl) => {
78 if (err) { 95 if (err) {
  96 + console.error(err)
79 res.send(err) 97 res.send(err)
80 - } else if (authUrl) {  
81 - console.info(authUrl)  
82 - res.send(authUrl)  
83 - res.end()  
84 } else { 98 } else {
85 lib.listEvents(auth, (err, response) => { 99 lib.listEvents(auth, (err, response) => {
86 if (err) { 100 if (err) {
87 - res.send(err) 101 + if (authUrl) {
  102 + console.info(authUrl)
  103 + res.json(responseJSON(res.code, "redirect to get auth code", authUrl, "redirect"))
  104 + res.end()
  105 + } else {
  106 + console.error(err)
  107 + res.json(responseJSON(res.code, "response error", err.message, "failed"))
  108 + res.end()
  109 + }
88 } else { 110 } else {
  111 + // console.info(response)
89 res.jsonp(ggToKendo(response)) 112 res.jsonp(ggToKendo(response))
  113 + res.end
90 } 114 }
91 }) 115 })
92 } 116 }
93 -  
94 }) 117 })
95 } 118 }
96 119
97 -function create(req, res) { 120 +function eventCreate(req, res) {
  121 + console.log(req.body)
98 let payload = req.body 122 let payload = req.body
  123 + if (typeof payload.models == "string") {
  124 + payload.models = JSON.parse(req.body.models)
  125 + payload = payload.models[0]
  126 + }
99 127
100 let summary = payload.summary 128 let summary = payload.summary
101 let description = payload.description 129 let description = payload.description
@@ -119,13 +147,90 @@ function create(req, res) { @@ -119,13 +147,90 @@ function create(req, res) {
119 res.send(err) 147 res.send(err)
120 } else { 148 } else {
121 res.send(result) 149 res.send(result)
  150 + res.end()
122 } 151 }
123 }) 152 })
124 }) 153 })
125 } 154 }
126 155
  156 +function oauth2callback(req, res) {
  157 + var code = req.query.code
  158 + lib.setNewToken(code, (err, token) => {
  159 + if (err) {
  160 + res.send(err)
  161 + res.end()
  162 + } else {
  163 + res.redirect('/home')
  164 + }
  165 + })
  166 +}
  167 +
  168 +function eventDelete(req, res) {
  169 + console.log(req.body)
  170 + let payload = req.body
  171 + if (typeof payload.models == "string") {
  172 + payload.models = JSON.parse(req.body.models)
  173 + payload = payload.models[0]
  174 + }
  175 + lib.authorize((err, auth) => {
  176 + let options = lib.deleteBuilder(payload)
  177 + if (err) {
  178 + console.error(err.message)
  179 + res.send(err)
  180 + } else {
  181 + console.info(auth)
  182 + options.auth = auth
  183 + }
  184 +
  185 + lib.deleteEvent(options, (err, result) => {
  186 + if (err) {
  187 + console.error(err.message)
  188 + res.send(err)
  189 + } else {
  190 + console.info(result)
  191 + res.send(result)
  192 + res.end()
  193 + }
  194 + })
  195 + })
  196 +}
  197 +
  198 +function eventUpdate(req, res) {
  199 + console.log(req.body)
  200 + let payload = req.body
  201 + if (typeof payload.models == "string") {
  202 + payload.models = JSON.parse(req.body.models)
  203 + payload = payload.models[0]
  204 + }
  205 + lib.authorize((err, auth) => {
  206 + let options = lib.updateBuilder(payload)
  207 + if (err) {
  208 + console.error(err.message)
  209 + res.send(err)
  210 + } else {
  211 + console.info(auth)
  212 + options.auth = auth
  213 + }
  214 +
  215 + lib.updateEvent(options, (err, result) => {
  216 + if (err) {
  217 + console.error(err)
  218 + res.send(err)
  219 + } else {
  220 + console.info(result)
  221 + res.send(result)
  222 + res.end()
  223 + }
  224 + })
  225 + })
  226 +}
  227 +
  228 +
127 module.exports.index = index 229 module.exports.index = index
128 module.exports.events = events 230 module.exports.events = events
129 -module.exports.create = create 231 +module.exports.eventCreate = eventCreate
  232 +module.exports.eventUpdate = eventUpdate
  233 +module.exports.eventDelete = eventDelete
130 module.exports.home = home 234 module.exports.home = home
131 module.exports.setToken = setToken 235 module.exports.setToken = setToken
  236 +module.exports.oauth2callback = oauth2callback
app/lib/index.js
@@ -7,7 +7,10 @@ const fs = require(&#39;fs&#39;); @@ -7,7 +7,10 @@ const fs = require(&#39;fs&#39;);
7 const path = require('path'); 7 const path = require('path');
8 const yamlConfig = require('node-yaml-config'); 8 const yamlConfig = require('node-yaml-config');
9 const config = yamlConfig.load(path.join(__dirname, '/../../config/config.yml')); 9 const config = yamlConfig.load(path.join(__dirname, '/../../config/config.yml'));
10 -const CALENDAR_ID = config.calendarID 10 +const moment = require('moment')
  11 +const CALENDAR_ID = config.ggapi.calendarID
  12 +const REDIRECTURL = config.ggapi.redirectUrl
  13 +
11 14
12 const SCOPES = ['https://www.googleapis.com/auth/calendar']; 15 const SCOPES = ['https://www.googleapis.com/auth/calendar'];
13 const TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) + '/.credentials/'; 16 const TOKEN_DIR = (process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE) + '/.credentials/';
@@ -63,9 +66,9 @@ module.exports = { @@ -63,9 +66,9 @@ module.exports = {
63 let credentials = JSON.parse(content); 66 let credentials = JSON.parse(content);
64 var clientSecret = credentials.installed.client_secret; 67 var clientSecret = credentials.installed.client_secret;
65 var clientId = credentials.installed.client_id; 68 var clientId = credentials.installed.client_id;
66 - var redirectUrl = credentials.installed.redirect_uris[0]; 69 + var redirectUrl = credentials.installed.redirect_uris[1];
67 var auth = new googleAuth(); 70 var auth = new googleAuth();
68 - var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); 71 + var oauth2Client = new auth.OAuth2(clientId, clientSecret, REDIRECTURL);
69 72
70 fs.readFile(TOKEN_PATH, (err, token) => { 73 fs.readFile(TOKEN_PATH, (err, token) => {
71 if (err) { 74 if (err) {
@@ -86,9 +89,9 @@ module.exports = { @@ -86,9 +89,9 @@ module.exports = {
86 let credentials = JSON.parse(content); 89 let credentials = JSON.parse(content);
87 var clientSecret = credentials.installed.client_secret; 90 var clientSecret = credentials.installed.client_secret;
88 var clientId = credentials.installed.client_id; 91 var clientId = credentials.installed.client_id;
89 - var redirectUrl = credentials.installed.redirect_uris[0]; 92 + var redirectUrl = credentials.installed.redirect_uris[1];
90 var auth = new googleAuth(); 93 var auth = new googleAuth();
91 - var oauth2Client = new auth.OAuth2(clientId, clientSecret, redirectUrl); 94 + var oauth2Client = new auth.OAuth2(clientId, clientSecret, REDIRECTURL);
92 95
93 fs.readFile(TOKEN_PATH, (err, token) => { 96 fs.readFile(TOKEN_PATH, (err, token) => {
94 if (err) { 97 if (err) {
@@ -115,7 +118,6 @@ module.exports = { @@ -115,7 +118,6 @@ module.exports = {
115 calendar.events.list({ 118 calendar.events.list({
116 auth: auth, 119 auth: auth,
117 calendarId: CALENDAR_ID || 'primary', 120 calendarId: CALENDAR_ID || 'primary',
118 - timeMin: (new Date()).toISOString(),  
119 maxResults: 50, 121 maxResults: 50,
120 singleEvents: true, 122 singleEvents: true,
121 orderBy: 'startTime' 123 orderBy: 'startTime'
@@ -150,19 +152,82 @@ module.exports = { @@ -150,19 +152,82 @@ module.exports = {
150 }); 152 });
151 }, 153 },
152 154
  155 + updateEvent: (options, callback) => {
  156 + calendar.events.update({
  157 + auth: options.auth,
  158 + calendarId: CALENDAR_ID || 'primary',
  159 + eventId: options.eventId
  160 + }, (err, response) => {
  161 + if (err) return callback(err);
  162 +
  163 + return callback(null, response);
  164 + });
  165 + },
  166 +
153 eventBuilder: (payload) => { 167 eventBuilder: (payload) => {
154 var buildPayload = {} 168 var buildPayload = {}
155 try { 169 try {
156 - buildPayload.summary = payload.summary  
157 - buildPayload.description = payload.description 170 + buildPayload.summary = payload.Title
  171 + buildPayload.description = payload.Description
158 buildPayload.start = { 172 buildPayload.start = {
159 - dateTime: payload.startDate,  
160 - timezone: hasTimezone(payload.startTimeZone) 173 + dateTime: payload.Start,
  174 + timezone: hasTimezone(payload.StartTimezone)
  175 +
  176 + }
  177 + buildPayload.end = {
  178 + dateTime: payload.End,
  179 + timeZone: hasTimezone(payload.EndTimezone)
  180 + }
  181 + if (payload.email) {
  182 + buildPayload.attendees = [{ email: payload.email }]
  183 + }
  184 + if (payload.reminders) {
  185 + buildPayload.reminders = {
  186 + useDefault: false,
  187 + overrides: [
  188 + {
  189 + method: 'email',
  190 + minutes: 24 * 60
  191 + }
  192 + ]
  193 + }
  194 + }
  195 + if (payload.extendedProperties) {
  196 + buildPayload.extendedProperties = payload.extendedProperties
  197 + }
  198 + } catch (error) {
  199 + console.error(error.message)
  200 + } finally {
  201 + return buildPayload
  202 + }
  203 + },
161 204
  205 + deleteBuilder: (payload) => {
  206 + var buildPayload = {}
  207 + try {
  208 + buildPayload.calendarId = CALENDAR_ID
  209 + buildPayload.eventId = payload.TaskID
  210 + } catch (error) {
  211 + console.error(error.message)
  212 + } finally {
  213 + return buildPayload
  214 + }
  215 + },
  216 +
  217 + updateBuilder: (payload) => {
  218 + var buildPayload = {}
  219 + try {
  220 + buildPayload.calendarId = CALENDAR_ID
  221 + buildPayload.eventId = payload.TaskID
  222 + buildPayload.summary = payload.Title
  223 + buildPayload.description = payload.Description
  224 + buildPayload.start = {
  225 + dateTime: moment(payload.Start).format("YYYY-MM-DDTHH:mm:ssZ"),
  226 + timeZone: hasTimezone(payload.StartTimezone)
162 } 227 }
163 buildPayload.end = { 228 buildPayload.end = {
164 - dateTime: payload.endDate,  
165 - timeZone: hasTimezone(payload.endTimeZone) 229 + dateTime: moment(payload.End).format("YYYY-MM-DDTHH:mm:ssZ"),
  230 + timeZone: hasTimezone(payload.EndTimezone)
166 } 231 }
167 if (payload.email) { 232 if (payload.email) {
168 buildPayload.attendees = [{ email: payload.email }] 233 buildPayload.attendees = [{ email: payload.email }]
app/routes/home.routes.js
@@ -7,7 +7,10 @@ router.get(&#39;/&#39;, home.index) @@ -7,7 +7,10 @@ router.get(&#39;/&#39;, home.index)
7 router.get('/home', home.home) 7 router.get('/home', home.home)
8 8
9 router.get('/events', home.events) 9 router.get('/events', home.events)
10 -router.post('/events', home.create) 10 +router.post('/events', home.eventCreate)
  11 +router.put('/events', home.eventUpdate)
  12 +router.delete('/events', home.eventDelete)
11 router.post('/setToken', home.setToken) 13 router.post('/setToken', home.setToken)
  14 +router.get('/oauth2callback', home.oauth2callback)
12 15
13 module.exports = router 16 module.exports = router
14 \ No newline at end of file 17 \ No newline at end of file
config/config.yml
@@ -15,4 +15,6 @@ localhost: @@ -15,4 +15,6 @@ localhost:
15 pass: 15 pass:
16 timerecheck: '10000' #millisecond 16 timerecheck: '10000' #millisecond
17 apitimeout: 3000 #millisecond 17 apitimeout: 3000 #millisecond
18 - calendarID: 'rvmbg3kg7uqninf7n3au1ku4mc@group.calendar.google.com'  
19 \ No newline at end of file 18 \ No newline at end of file
  19 + ggapi:
  20 + calendarID: 'rvmbg3kg7uqninf7n3au1ku4mc@group.calendar.google.com'
  21 + redirectUrl: 'http://localhost:3001/oauth2callback'
20 \ No newline at end of file 22 \ No newline at end of file
public/js/controllers/kendo.js
1 angular.module("KendoDemos", ["kendo.directives"]) 1 angular.module("KendoDemos", ["kendo.directives"])
2 .controller("MyCtrl", function ($scope, $http) { 2 .controller("MyCtrl", function ($scope, $http) {
  3 + $scope.update = function () {
  4 + console.log("update")
  5 + }
  6 +
  7 + $scope.create = function () {
  8 + console.log("create")
  9 + }
3 function getAuthURL() { 10 function getAuthURL() {
4 $http({ 11 $http({
5 method: 'get', 12 method: 'get',
6 url: '/events' 13 url: '/events'
7 }).then(function successCallback(response) { 14 }).then(function successCallback(response) {
8 - window.open(response.data, '_blank')  
9 - }, function errorCallback(response) {  
10 - console.error(response)  
11 - });  
12 - }  
13 - getAuthURL() 15 + var res = response.data
  16 + if (res.result) {
  17 + if (res.result.status == "redirect") {
  18 + window.open(res.result.data, '_self')
  19 + }
  20 + } else {
  21 + console.info(response)
  22 + schedulerStart()
  23 + }
14 24
15 - $scope.submitNewToken = function (valid) {  
16 - $http({  
17 - method: 'post',  
18 - url: '/setToken',  
19 - data: { "code": $scope.clientToken }  
20 - }).then(function successCallback(response) {  
21 - console.log(response.data)  
22 - schedulerStart()  
23 }, function errorCallback(response) { 25 }, function errorCallback(response) {
24 console.error(response) 26 console.error(response)
25 }); 27 });
26 } 28 }
  29 + getAuthURL()
27 30
28 function schedulerStart() { 31 function schedulerStart() {
29 $scope.schedulerOptions = { 32 $scope.schedulerOptions = {
@@ -36,25 +39,29 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;]) @@ -36,25 +39,29 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;])
36 "week", 39 "week",
37 "month", 40 "month",
38 ], 41 ],
39 - timezone: "Etc/UTC", 42 + timezone: "Asia/Bangkok",
40 dataSource: { 43 dataSource: {
41 batch: true, 44 batch: true,
42 transport: { 45 transport: {
43 read: { 46 read: {
44 url: "//localhost:3001/events", 47 url: "//localhost:3001/events",
45 - dataType: "jsonp" 48 + dataType: "jsonp",
  49 + type: "GET"
46 }, 50 },
47 update: { 51 update: {
48 - url: "//demos.telerik.com/kendo-ui/service/tasks/update",  
49 - dataType: "jsonp" 52 + url: "//localhost:3001/events",
  53 + dataType: "jsonp",
  54 + type: "PUT"
50 }, 55 },
51 create: { 56 create: {
52 - url: "//demos.telerik.com/kendo-ui/service/tasks/create",  
53 - dataType: "jsonp" 57 + url: "//localhost:3001/events",
  58 + dataType: "jsonp",
  59 + type: "POST"
54 }, 60 },
55 destroy: { 61 destroy: {
56 - url: "//demos.telerik.com/kendo-ui/service/tasks/destroy",  
57 - dataType: "jsonp" 62 + url: "//localhost:3001/events",
  63 + dataType: "jsonp",
  64 + type: "DELETE"
58 }, 65 },
59 parameterMap: function (options, operation) { 66 parameterMap: function (options, operation) {
60 if (operation !== "read" && options.models) { 67 if (operation !== "read" && options.models) {
@@ -68,10 +75,10 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;]) @@ -68,10 +75,10 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;])
68 fields: { 75 fields: {
69 taskId: { from: "TaskID" }, 76 taskId: { from: "TaskID" },
70 title: { from: "Title", defaultValue: "No title", validation: { required: true } }, 77 title: { from: "Title", defaultValue: "No title", validation: { required: true } },
71 - start: { type: "date", from: "Start" },  
72 - end: { type: "date", from: "End" },  
73 - startTimezone: { from: "StartTimezone" },  
74 - endTimezone: { from: "EndTimezone" }, 78 + start: { type: "datetime", from: "Start" },
  79 + end: { type: "datetime", from: "End" },
  80 + startTimezone: { from: "StartTimezone", defaultValue: "Asia/Bangkok" },
  81 + endTimezone: { from: "EndTimezone", defaultValue: "Asia/Bangkok" },
75 description: { from: "Description" }, 82 description: { from: "Description" },
76 recurrenceId: { from: "RecurrenceID" }, 83 recurrenceId: { from: "RecurrenceID" },
77 recurrenceRule: { from: "RecurrenceRule" }, 84 recurrenceRule: { from: "RecurrenceRule" },
@@ -89,6 +96,7 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;]) @@ -89,6 +96,7 @@ angular.module(&quot;KendoDemos&quot;, [&quot;kendo.directives&quot;])
89 ] 96 ]
90 } 97 }
91 }, 98 },
  99 + editable: true,
92 resources: [ 100 resources: [
93 { 101 {
94 field: "ownerId", 102 field: "ownerId",
public/views/index.html
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <link href="../assets/content/shared/styles/examples-offline.css" rel="stylesheet"> 7 <link href="../assets/content/shared/styles/examples-offline.css" rel="stylesheet">
8 <link href="../assets/styles/kendo.common.min.css" rel="stylesheet"> 8 <link href="../assets/styles/kendo.common.min.css" rel="stylesheet">
9 <link href="../assets/styles/kendo.rtl.min.css" rel="stylesheet"> 9 <link href="../assets/styles/kendo.rtl.min.css" rel="stylesheet">
10 - <link href="../assets/styles/kendo.flat.min.css" rel="stylesheet"> 10 + <link href="../assets/styles/kendo.bootstrap.min.css" rel="stylesheet">
11 <link href="../assets/styles/kendo.dataviz.min.css" rel="stylesheet"> 11 <link href="../assets/styles/kendo.dataviz.min.css" rel="stylesheet">
12 <link href="../assets/styles/kendo.dataviz.flat.min.css" rel="stylesheet"> 12 <link href="../assets/styles/kendo.dataviz.flat.min.css" rel="stylesheet">
13 <script src="../assets/js/jquery.min.js"></script> 13 <script src="../assets/js/jquery.min.js"></script>
@@ -27,22 +27,8 @@ @@ -27,22 +27,8 @@
27 27
28 <body> 28 <body>
29 29
30 - <a class="offline-button" href="../assets/offline/index.html">Back</a>  
31 -  
32 <div id="example" ng-app="KendoDemos"> 30 <div id="example" ng-app="KendoDemos">
33 <div ng-controller="MyCtrl"> 31 <div ng-controller="MyCtrl">
34 - <form class="demo-section k-content wide" name="newTokenForm" ng-submit="submitNewToken(newTokenForm.$valid)">  
35 - <ul class="fieldlist">  
36 - <li>  
37 - <h4>Put key here</h4>  
38 - <input type="text" class="k-textbox " ng-model="clientToken" required />  
39 - <input type="submit" class="k-button" name="btnSubmitKey" value="Submit">  
40 - </li>  
41 - </ul>  
42 - </form>  
43 -  
44 - <hr>  
45 -  
46 <div kendo-scheduler k-options="schedulerOptions"> 32 <div kendo-scheduler k-options="schedulerOptions">
47 <span k-event-template class="custom-event">{{dataItem.title}}</span> 33 <span k-event-template class="custom-event">{{dataItem.title}}</span>
48 <div k-all-day-event-template class="custom-all-day-event">{{dataItem.title}}</div> 34 <div k-all-day-event-template class="custom-all-day-event">{{dataItem.title}}</div>