Merge pull request #175 from h3poteto/iss-174

closes #174 Save account username in local db
This commit is contained in:
AkiraFukushima 2018-04-01 22:03:52 +09:00 committed by GitHub
commit 9ed309ec1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 130 additions and 74 deletions

View File

@ -5,6 +5,16 @@ export default class Account {
this.db = db
}
insertAccount (obj) {
return new Promise((resolve, reject) => {
this.db.insert(obj, (err, doc) => {
if (err) return reject(err)
if (empty(doc)) return reject(new EmptyRecordError('empty'))
resolve(doc)
})
})
}
listAccounts () {
return new Promise((resolve, reject) => {
this.db.find({accessToken: { $ne: '' }}, (err, docs) => {
@ -29,6 +39,42 @@ export default class Account {
)
})
}
searchAccount (obj) {
return new Promise((resolve, reject) => {
this.db.findOne(
obj,
(err, doc) => {
if (err) return reject(err)
if (empty(doc)) return reject(new EmptyRecordError('empty'))
resolve(doc)
})
})
}
updateAccount (id, obj) {
return new Promise((resolve, reject) => {
this.db.update(
{
_id: id
},
{ $set: Object.assign(obj, { _id: id }) },
{ multi: true },
(err, numReplaced) => {
if (err) return reject(err)
this.db.findOne(
{
_id: id
},
(err, doc) => {
if (err) return reject(err)
if (empty(doc)) return reject(new EmptyRecordError('empty'))
resolve(doc)
})
}
)
})
}
}
class EmptyRecordError {

View File

@ -1,12 +1,11 @@
import Mastodon from 'mastodon-api'
import log from 'electron-log'
const appName = 'whalebird'
const scope = 'read write follow'
export default class Authentication {
constructor (db) {
this.db = db
constructor (accountDB) {
this.db = accountDB
this.baseURL = ''
this.domain = ''
this.clientId = ''
@ -21,46 +20,38 @@ export default class Authentication {
this.clientSecret = ''
}
getAuthorizationUrl (domain = 'mastodon.social') {
async getAuthorizationUrl (domain = 'mastodon.social') {
this.setOtherInstance(domain)
return Mastodon.createOAuthApp(this.baseURL + '/api/v1/apps', appName, scope)
.catch(err => log.error(err))
.then((res) => {
this.clientId = res.client_id
this.clientSecret = res.client_secret
const res = await Mastodon.createOAuthApp(this.baseURL + '/api/v1/apps', appName, scope)
this.clientId = res.client_id
this.clientSecret = res.client_secret
const json = {
baseURL: this.baseURL,
domain: this.domain,
clientId: this.clientId,
clientSecret: this.clientSecret,
accessToken: ''
}
this.db.insert(json, (err, _) => {
if (err) throw err
})
return Mastodon.getAuthorizationUrl(this.clientId, this.clientSecret, this.baseURL)
})
// TODO: Save order number
const json = {
baseURL: this.baseURL,
domain: this.domain,
clientId: this.clientId,
clientSecret: this.clientSecret,
accessToken: '',
username: '',
accountId: ''
}
await this.db.insertAccount(json)
const url = await Mastodon.getAuthorizationUrl(this.clientId, this.clientSecret, this.baseURL)
return url
}
getAccessToken (code) {
return new Promise((resolve, reject) => {
Mastodon.getAccessToken(this.clientId, this.clientSecret, code, this.baseURL)
.catch(err => reject(err))
.then((token) => {
const search = {
baseURL: this.baseURL,
domain: this.domain,
clientId: this.clientId,
clientSecret: this.clientSecret
}
this.db.update(search, {$set: { accessToken: token }}, {}, (err, num) => {
if (err) return reject(err)
resolve(token)
})
})
})
async getAccessToken (code) {
const token = await Mastodon.getAccessToken(this.clientId, this.clientSecret, code, this.baseURL)
const search = {
baseURL: this.baseURL,
domain: this.domain,
clientId: this.clientId,
clientSecret: this.clientSecret
}
const rec = await this.db.searchAccount(search)
await this.db.updateAccount(rec._id, { accessToken: token })
return token
}
// TODO: Refresh access token when expired
}

View File

@ -32,8 +32,8 @@ const winURL = process.env.NODE_ENV === 'development'
// https://github.com/louischatriot/nedb/issues/459
const userData = app.getPath('userData')
const databasePath = process.env.NODE_ENV === 'production'
? userData + '/db/whalebird.db'
: 'whalebird.db'
? userData + '/db/account.db'
: 'account.db'
let db = new Datastore({
filename: databasePath,
autoload: true
@ -208,20 +208,20 @@ app.on('activate', () => {
}
})
let auth = new Authentication(db)
let auth = new Authentication(new Account(db))
ipcMain.on('get-auth-url', (event, domain) => {
auth.getAuthorizationUrl(domain)
.catch((err) => {
log.error(err)
event.sender.send('error-get-auth-url', err)
})
.then((url) => {
log.debug(url)
event.sender.send('response-get-auth-url', url)
// Open authorize url in default browser.
shell.openExternal(url)
})
.catch((err) => {
log.error(err)
event.sender.send('error-get-auth-url', err)
})
})
ipcMain.on('get-access-token', (event, code) => {
@ -275,6 +275,19 @@ ipcMain.on('get-local-account', (event, id) => {
})
})
ipcMain.on('update-account', (event, acct) => {
const account = new Account(db)
const id = acct._id
delete acct._id
account.updateAccount(id, acct)
.then((ac) => {
event.sender.send('response-update-account', ac)
})
.catch((err) => {
event.sender.send('error-update-account', err)
})
})
// streaming
let userStreaming = null

View File

@ -41,7 +41,6 @@ export default {
methods: {
async clear () {
await this.$store.dispatch('TimelineSpace/clearAccount')
await this.$store.dispatch('TimelineSpace/clearUsername')
await this.$store.dispatch('TimelineSpace/clearTimeline')
await this.$store.dispatch('TimelineSpace/clearNotifications')
await this.$store.dispatch('TimelineSpace/removeShortcutEvents')
@ -52,7 +51,7 @@ export default {
this.$store.dispatch('TimelineSpace/watchShortcutEvents')
try {
const account = await this.$store.dispatch('TimelineSpace/fetchAccount', this.$route.params.id)
const account = await this.$store.dispatch('TimelineSpace/localAccount', this.$route.params.id)
try {
await this.$store.dispatch('TimelineSpace/fetchHomeTimeline', account)
} catch (err) {
@ -61,14 +60,6 @@ export default {
type: 'error'
})
}
try {
await this.$store.dispatch('TimelineSpace/username', account)
} catch (err) {
this.$message({
message: 'Could not fetch username',
type: 'error'
})
}
try {
await this.$store.dispatch('TimelineSpace/fetchNotifications', account)
} catch (err) {

View File

@ -2,7 +2,7 @@
<div id="side_menu">
<div class="profile-wrapper" style="-webkit-app-region: drag;">
<div class="profile">
<div>@{{ username }}</div>
<div>@{{ account.username }}</div>
<span>{{ account.domain }}</span>
</div>
</div>
@ -49,7 +49,6 @@ export default {
computed: {
...mapState({
account: state => state.TimelineSpace.account,
username: state => state.TimelineSpace.username,
unreadHomeTimeline: state => state.TimelineSpace.SideMenu.unreadHomeTimeline,
unreadNotifications: state => state.TimelineSpace.SideMenu.unreadNotifications
})

View File

@ -15,9 +15,9 @@ const TimelineSpace = {
state: {
account: {
domain: '',
_id: ''
_id: '',
username: ''
},
username: '',
homeTimeline: [],
notifications: []
},
@ -25,9 +25,6 @@ const TimelineSpace = {
updateAccount (state, account) {
state.account = account
},
updateUsername (state, username) {
state.username = username
},
appendHomeTimeline (state, update) {
state.homeTimeline = [update].concat(state.homeTimeline)
},
@ -90,7 +87,7 @@ const TimelineSpace = {
}
},
actions: {
fetchAccount ({ commit }, id) {
localAccount ({ dispatch, commit }, id) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-local-account', id)
ipcRenderer.once('error-get-local-account', (event, err) => {
@ -99,12 +96,24 @@ const TimelineSpace = {
})
ipcRenderer.once('response-get-local-account', (event, account) => {
ipcRenderer.removeAllListeners('error-get-local-account')
commit('updateAccount', account)
resolve(account)
if (account.username === undefined || account.username === null || account.username === '') {
dispatch('fetchAccount', account)
.then((acct) => {
commit('updateAccount', acct)
resolve(acct)
})
.catch((err) => {
reject(err)
})
} else {
commit('updateAccount', account)
resolve(account)
}
})
})
},
username ({ commit }, account) {
fetchAccount ({ commit }, account) {
return new Promise((resolve, reject) => {
const client = new Mastodon(
{
@ -113,8 +122,18 @@ const TimelineSpace = {
})
client.get('/accounts/verify_credentials', (err, data, res) => {
if (err) return reject(err)
commit('updateUsername', data.username)
resolve(res)
ipcRenderer.send('update-account', Object.assign(account, {
username: data.username,
accountId: data.id
}))
ipcRenderer.once('error-update-account', (event, err) => {
ipcRenderer.removeAllListeners('response-update-account')
reject(err)
})
ipcRenderer.once('response-update-account', (event, account) => {
ipcRenderer.removeAllListeners('error-update-account')
resolve(account)
})
})
})
},
@ -202,14 +221,11 @@ const TimelineSpace = {
'updateAccount',
{
domain: '',
_id: ''
_id: '',
username: ''
}
)
return 'clearAccount'
},
async clearUsername ({ commit }) {
commit('updateUsername', '')
return 'clearUsername'
}
}
}