-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature(social Oauth):add social media login route #29
Conversation
src/routes/index.js
Outdated
@@ -2,4 +2,4 @@ const router = require("express").Router(); | |||
|
|||
router.use("/api", require("./api")); | |||
|
|||
module.exports = router; | |||
export default router; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing error: 'import' and 'export' may appear only with 'sourceType: module'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A add a new line here.
src/config/passport.js
Outdated
@@ -0,0 +1,17 @@ | |||
import passport from "passport"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing error: 'import' and 'export' may appear only with 'sourceType: module'
src/config/keys.js
Outdated
@@ -0,0 +1,8 @@ | |||
import dotenv from 'dotenv'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing error: 'import' and 'export' may appear only with 'sourceType: module'
eb31152
to
8bd5891
Compare
src/utils/helpers.js
Outdated
@@ -0,0 +1,7 @@ | |||
class Helper { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
src/routes/v1/socialRoutes.js
Outdated
router.get('/facebook/redirect', | ||
passport.authenticate('facebook', { | ||
session: false | ||
}), SocialController.socialLogin); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline before ')' function-paren-newline
src/routes/v1/socialRoutes.js
Outdated
scope: ['profile'] | ||
})); | ||
|
||
router.get('/facebook/redirect', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline after '(' function-paren-newline
src/routes/v1/socialRoutes.js
Outdated
router.get('/google/redirect', | ||
passport.authenticate('google', { | ||
session: false | ||
}), SocialController.socialLogin); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline before ')' function-paren-newline
src/controllers/socialController.js
Outdated
} | ||
}); | ||
} catch (error) { | ||
console.log(error.message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected console statement no-console
src/controllers/socialController.js
Outdated
try { | ||
const { | ||
_json: user, | ||
provider |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'provider' is assigned a value but never used no-unused-vars
src/controllers/socialController.js
Outdated
config(); | ||
|
||
class SocialController { | ||
static async socialLogin(req, res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
|
||
config(); | ||
|
||
class SocialController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
src/controllers/socialController.js
Outdated
import jwt from 'jsonwebtoken'; | ||
import { | ||
config | ||
} from 'dotenv'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
8bd5891
to
4e371e5
Compare
src/controllers/socialController.js
Outdated
@@ -0,0 +1,57 @@ | |||
import jwt from 'jsonwebtoken'; | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love the way you created a new file for this and for also following the naming convention. 👍
clientID: FACEBOOK_CLIENT_ID, | ||
clientSecret: FACEBOOK_CLIENT_SECRET | ||
}, passportCb) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline before ')' function-paren-newline
clientSecret: GOOGLE_CLIENT_SECRET | ||
}, passportCb) | ||
); | ||
passport.use( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
clientID: GOOGLE_CLIENT_ID, | ||
clientSecret: GOOGLE_CLIENT_SECRET | ||
}, passportCb) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline before ')' function-paren-newline
} = env; | ||
|
||
const setupPassport = () => { | ||
passport.use( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
src/config/passport.js
Outdated
import passport from 'passport'; | ||
import { | ||
Strategy as GoogleStrategy | ||
} from 'passport-google-oauth20'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
src/config/passport.js
Outdated
@@ -0,0 +1,44 @@ | |||
import passport from 'passport'; | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
4e371e5
to
f96514e
Compare
src/controllers/socialController.js
Outdated
first_name, | ||
} = user; | ||
const userData = await SocialController.findOrCreateUserByEmail(first_name, last_name, email); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 80 exceeds the maximum line length of 80 max-len
src/controllers/socialController.js
Outdated
|
||
const { | ||
last_name, | ||
first_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Identifier 'first_name' is not in camel case camelcase
src/controllers/socialController.js
Outdated
} | ||
|
||
const { | ||
last_name, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Identifier 'last_name' is not in camel case camelcase
src/controllers/socialController.js
Outdated
_raw, | ||
_json: user | ||
} = req.user; | ||
console.log(user); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected console statement no-console
src/controllers/socialController.js
Outdated
static async facebookLogin(req, res) { | ||
try { | ||
const { | ||
_raw, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'_raw' is assigned a value but never used no-unused-vars
} | ||
} | ||
|
||
static async facebookLogin(req, res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
src/controllers/socialController.js
Outdated
} | ||
}); | ||
} catch (error) { | ||
console.log(error.message); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected console statement no-console
src/controllers/socialController.js
Outdated
error: 'No email address is found for this user' | ||
}); | ||
} | ||
const userData = await SocialController.findOrCreateUserByEmail(user.firstName, user.lastName, user.email); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 39 exceeds the maximum line length of 80 max-len
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, just login not to create a user.
return userData; | ||
} | ||
|
||
static async googleLogin(req, res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add a JSDOC. look at other controllers to see how we have been writing JSDOCs for controller
src/config/passport.js
Outdated
callbackURL: 'http://localhost:3000/api/v1/auth/facebook/redirect', | ||
clientID: FACEBOOK_CLIENT_ID, | ||
clientSecret: FACEBOOK_CLIENT_SECRET, | ||
profileFields: ['id', 'email', 'gender', 'link', 'locale', 'name', 'timezone', 'updated_time', 'verified'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 34 exceeds the maximum line length of 80 max-len
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix this hound error by doing
[
'id', 'email', 'gender', 'link', 'locale',
'name', 'timezone', 'updated_time', 'verified'
];
.sequelizerc
Outdated
@@ -1,5 +1,7 @@ | |||
require('@babel/register'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why are you importing babel register in here?
.sequelizerc
Outdated
const path = require('path'); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why did you add a new line here?.
src/config/env-config.js
Outdated
env | ||
} = process; | ||
|
||
export default env; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this file created?. Is it necessary?
src/config/passport.js
Outdated
Strategy as GoogleStrategy | ||
} from 'passport-google-oauth20'; | ||
import env from './env-config'; | ||
import Helpers from '../utils/helpers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not how we have been importing helpermethods in the codebase. Please import it correctly.
src/controllers/socialController.js
Outdated
error: 'No email address is found for this user' | ||
}); | ||
} | ||
const userData = await SocialController.findOrCreateUserByEmail(user.firstName, user.lastName, user.email); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, just login not to create a user.
src/routes/index.js
Outdated
@@ -2,4 +2,4 @@ const router = require("express").Router(); | |||
|
|||
router.use("/api", require("./api")); | |||
|
|||
module.exports = router; | |||
export default router; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A add a new line here.
f96514e
to
afa891b
Compare
src/utils/helpers.js
Outdated
* @param {string} done - user profile | ||
* @return {object} - user profile | ||
*/ | ||
export const passportCb = (accessToken, requestToken, profile, done) => done(null, profile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 9 exceeds the maximum line length of 90 max-len
Prefer default export import/prefer-default-export
@@ -0,0 +1,3 @@ | |||
import sinon from 'sinon'; | |||
import chai from 'chai'; | |||
import passport from 'passport'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'passport' is defined but never used no-unused-vars
@@ -0,0 +1,3 @@ | |||
import sinon from 'sinon'; | |||
import chai from 'chai'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'chai' is defined but never used no-unused-vars
@@ -0,0 +1,3 @@ | |||
import sinon from 'sinon'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'sinon' is defined but never used no-unused-vars
import { SendEmail } from '../../utils'; | ||
import { | ||
SendEmail | ||
} from '../../utils'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
scope: ['profile', 'email'] | ||
})); | ||
|
||
app.get('/api/v1/auth/google/redirect', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline after '(' function-paren-newline
src/routes/requestRoute.js
Outdated
@@ -9,4 +11,4 @@ const requestRoutes = app => { | |||
RequestController.bookATrip); | |||
}; | |||
|
|||
export default requestRoutes; | |||
export default requestRoutes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newline required at end of file but not found eol-last
src/routes/requestRoute.js
Outdated
import { RequestController } from '../controllers'; | ||
import { | ||
RequestController | ||
} from '../controllers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
src/routes/requestRoute.js
Outdated
@@ -1,4 +1,6 @@ | |||
import { RequestController } from '../controllers'; | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
import { CryptData } from '../utils'; | ||
import { | ||
CryptData | ||
} from '../utils'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
afa891b
to
339d986
Compare
@@ -1,4 +1,6 @@ | |||
import { CryptData } from '../utils'; | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
import app from '../../index'; | ||
import { | ||
passportCb | ||
} from '../../utils/helpers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
import chaiHttp from 'chai-http'; | ||
import passport from 'passport'; | ||
import app from '../../index'; | ||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
src/config/passport.js
Outdated
callbackURL: 'http://localhost:3000/api/v1/auth/facebook/redirect', | ||
clientID: FACEBOOK_CLIENT_ID, | ||
clientSecret: FACEBOOK_CLIENT_SECRET, | ||
profileFields: ['id', 'email', 'gender', 'link', 'locale', 'name', 'timezone', 'updated_time', 'verified'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 34 exceeds the maximum line length of 90 max-len
src/controllers/socialController.js
Outdated
value: userEmail | ||
}] = emails; | ||
if (!userEmail) { | ||
return HelperMethods.clientError(res, 'No email address is found for this user', 400); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 91 exceeds the maximum line length of 90 max-len
src/controllers/socialController.js
Outdated
static async facebookLogin(req, res) { | ||
try { | ||
const { | ||
_json: user, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'user' is assigned a value but never used no-unused-vars
src/controllers/socialController.js
Outdated
value: userEmail | ||
}] = emails; | ||
if (!userEmail) { | ||
return HelperMethods.clientError(res, 'No email address is found for this user', 400); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 51 exceeds the maximum line length of 90 max-len
src/controllers/socialController.js
Outdated
// check if user exist | ||
try { | ||
const { | ||
_json: user, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'user' is assigned a value but never used no-unused-vars
339d986
to
39e43bd
Compare
* @memberof socialController | ||
*/ | ||
|
||
static async googleLogin(req, res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
|
||
dotenv.config(); | ||
|
||
class SocialController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing JSDoc comment require-jsdoc
39e43bd
to
7c55c71
Compare
import { UserController } from '../../controllers'; | ||
import { | ||
UserController | ||
} from '../../controllers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
src/routes/userRoute.js
Outdated
import { UserController } from '../controllers'; | ||
import { | ||
UserController | ||
} from '../controllers'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break before this closing brace object-curly-newline
src/routes/userRoute.js
Outdated
@@ -1,4 +1,6 @@ | |||
import { UserController } from '../controllers'; | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected line break after this opening brace object-curly-newline
src/seeders/01-demo-user.js
Outdated
createdAt: new Date(), | ||
updatedAt: new Date() | ||
}, | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected indentation of 2 spaces but found 4 indent
src/seeders/01-demo-user.js
Outdated
password: await init(), | ||
createdAt: new Date(), | ||
updatedAt: new Date() | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected indentation of 2 spaces but found 4 indent
src/seeders/01-demo-user.js
Outdated
username: 'user2', | ||
password: await init(), | ||
createdAt: new Date(), | ||
updatedAt: new Date() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected indentation of 4 spaces but found 6 indent
@@ -68,4 +71,4 @@ | |||
"nyc": "^14.1.1", | |||
"sinon": "^7.4.1" | |||
} | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a new line here.
732d57b
to
9a4f9d7
Compare
9a4f9d7
to
b2e0742
Compare
}; | ||
|
||
export default routes; | ||
export default routes; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Newline required at end of file but not found eol-last
if (!userData) { | ||
return HelperMethods.clientError(res, | ||
'You are not a registered user. Please, signup', | ||
404); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline before ')' function-paren-newline
} | ||
const userData = await SocialController.findByEmail(userEmail); | ||
if (!userData) { | ||
return HelperMethods.clientError(res, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline after '(' function-paren-newline
if (!userEmail) { | ||
return HelperMethods.clientError(res, | ||
'No email address is found for this user', | ||
400); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline before ')' function-paren-newline
try { | ||
const [{ value: userEmail }] = req.user.emails; | ||
if (!userEmail) { | ||
return HelperMethods.clientError(res, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Expected a newline after '(' function-paren-newline
try { | ||
const [{ value: userEmail }] = req.user.emails; | ||
if (!userEmail) { | ||
return HelperMethods.clientError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
'name', 'timezone', 'updated_time', 'verified' | ||
], | ||
}, passportCb) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline before ')' function-paren-newline
clientSecret: GOOGLE_CLIENT_SECRET | ||
}, passportCb) | ||
); | ||
passport.use( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
clientID: GOOGLE_CLIENT_ID, | ||
clientSecret: GOOGLE_CLIENT_SECRET | ||
}, passportCb) | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline before ')' function-paren-newline
const passportCb = (accessToken, requestToken, profile, done) => done(null, profile); | ||
|
||
const setupPassport = () => { | ||
passport.use( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
b2e0742
to
f59c47c
Compare
*/ | ||
export const passportCb = (accessToken, requestToken, profile, done) => done( | ||
null, profile | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline before ')' function-paren-newline
* @param {string} done - user profile | ||
* @return {object} - user profile | ||
*/ | ||
export const passportCb = (accessToken, requestToken, profile, done) => done( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unexpected newline after '(' function-paren-newline
What does this PR do?
Description of Task to be completed?
How should this be manually tested?
cd
into the project directoryyarn install
to install the project's dependencyyarn start
to start the appWhat are the relevant pivotal tracker stories?
#167727629
Screenshot