Instagram service update; other

This commit is contained in:
tmshv committed 2016-03-24 23:52:26 +03:00
1 parent 6655a5fca8
commit a756d6c5d3
15 files changed
+191 -38

No files matched your search

+3
View File
@@ -11,7 +11,9 @@
"babel-preset-es2015": "^6.6.0",
"babel-preset-stage-0": "^6.5.0",
"co": "^4.6.0",
"ejson": "^2.1.2",
"instagram-node": "^0.5.8",
"jsonwebtoken": "^5.7.0",
"kerberos": "0.0.19",
"koa": "^2.0.0-alpha.3",
"koa-bodyparser": "^3.0.0",
@@ -25,6 +27,7 @@
"mz": "^2.3.1",
"react": "^0.14.7",
"react-dom": "^0.14.7",
"react-router": "^2.0.1",
"thunkify": "^2.1.2"
},
"devDependencies": {
+2 -2
View File
@@ -1,5 +1,5 @@
export default class EndPoint{
constructor() {
constructor(request) {
this.request = request;
}
}
+1 -3
View File
@@ -2,8 +2,6 @@ import EndPoint from './EndPoint';
export default class Feed extends EndPoint {
add(post) {
return new Promise((resolve, reject) => {
});
return this.request.request('PUT', '/feed', post);
}
}
+24 -6
View File
@@ -1,15 +1,33 @@
import {stringify} from 'ejson';
import {EventEmitter} from 'events';
import request from 'request-promise';
import Feed from './Feed';
export default class Service extends EventEmitter{
constructor(secret) {
super();
let json = i => stringify(i);
export default class Service extends EventEmitter{
constructor(host, service, secret) {
super();
this.version = 'v1';
this.host = host;
this.service = service;
this.secret = secret;
this.feed = new Feed(this.request);
this.feed = new Feed(this);
}
request(){
request(method, path, data) {
let buildPath = path => `${this.host}/api/${this.version}${path}`;
let options = {
method: method,
uri: buildPath(path),
headers: {
'Content-Type': 'application/ejson',
'X-Service-Name': this.service,
'X-Service-Token': this.secret
},
body: json(data)
};
return request(options);
}
}
+21 -4
View File
@@ -1,8 +1,25 @@
import React from 'react';
import ReactDOM from 'react-dom';
import {render} from 'react-dom';
import {Router, Route, browserHistory} from 'react-router';
import App from './components/App';
ReactDOM.render(
<App/>,
document.querySelector('.app-container')
render(
(
<Router history={browserHistory}>
<Route path="/" component={App}>
</Route>
</Router>
),
document.querySelector('.app-container')
);
// <Route path="login" component={Login}/>
// <Route path="logout" component={Logout}/>
// <Route path="about" component={About}/>
// <Route path="dashboard" component={Dashboard} onEnter={requireAuth}/>
// render(
// <App/>,
// document.querySelector('.app-container')
// );
+12 -1
View File
@@ -1,7 +1,18 @@
import React from 'react';
export default class App extends React.Component{
handleClick(event){
}
render(){
return (<h1>Hi</h1>)
return (
<div>
<h1>Панель управления инстаграмом художки</h1>
<p>Чтобы управлять, вы должны быть <a href="https://instagram.com/hudozka">hudozka</a></p>
<a href="/auth" onClick={this.handleClick.bind(this)}>Войти</a>
</div>
)
}
}
+11 -4
View File
@@ -16,8 +16,15 @@ export const clientId = privateData['clientId'];
export const clientSecret = privateData['clientSecret'];
export const redirectUri = privateData['redirectUri'];
export const serviceHost = isProduction ? 'http://localhost:1800' : 'http://localhost:8080';
export const serviceName = 'instagram';
export const serviceSecret = privateData['serviceSecret'];
export const jwtSecret = privateData['jwtSecret'];
export const sessionSecret = privateData['sessionSecret'];
export const sessionExpirationTime = 60 * 60 * 24 * 2; // two days in seconds
export const authScope = [
'basic',
// 'public_content',
@@ -27,9 +34,10 @@ export const authScope = [
'likes'
];
export const sessionSecret = privateData['sessionSecret'];
// export const sessionExpirationTime = 60 * 60 * 24 * 2; // two days in seconds
export const sessionExpirationTime = 10; // 10 seconds
export const postType = 'instagram-2';
export const fetchItemsPerUpdateLoop = 1;
export const updateSubscriptionDelay = 1000 * 60 * 60; // one hour in milliseconds
export const updateSubscriptionCallbackUrl = isProduction ? `https://art.shburg.org${pathPrefix}/callback/hudozka` : 'http://dev.tmshv.ru/callback/hudozka';
export const database = {
host: 'localhost',
@@ -40,4 +48,3 @@ export const database = {
};
export const databaseUri = `mongodb://${database.host}:${database.port}/${database.db}`;
+12
View File
@@ -1,4 +1,6 @@
import {collection} from './db';
import {jwtSecret} from '../config';
import {sign} from 'jsonwebtoken';
/**
* {
@@ -27,6 +29,7 @@ export async function authorizeUser(accessToken, user) {
profile[i] = user[i];
});
profile.accessToken = accessToken;
profile.jwtToken = await createToken(profile);
await users.update({_id: profile['_id']}, profile);
return profile;
@@ -34,3 +37,12 @@ export async function authorizeUser(accessToken, user) {
return null;
}
}
async function createToken(user){
return new Promise((resolve, reject) => {
sign(user, jwtSecret, {}, token => {
if (!token) return reject();
resolve(token);
});
});
}
+54 -5
View File
@@ -2,9 +2,9 @@ import {collection} from './db';
import {api} from '../instagram';
import {postFromInstagramMedia} from '../models/post';
import Service from '../api/Service';
import {serviceSecret} from '../config';
import {serviceHost, serviceName, serviceSecret, fetchItemsPerUpdateLoop as num} from '../config';
const service = new Service(serviceSecret);
const service = new Service(serviceHost, serviceName, serviceSecret);
var instagramClient;
@@ -15,14 +15,63 @@ export default async function update(id, data) {
let data = await instagram.user.mediaRecent(null, 1, updateTimestamp);
let items = data.medias.map(postFromInstagramMedia);
for (let post of items) {
await service.feed.add(post);
}
return await Promise.all(
items.map(post => service.feed.add(post))
);
} catch (e) {
console.log(e);
}
}
export async function clearSubscriptions(callbackUrl) {
const instagram = await client();
return await instagram.subscriptions.removeAll();
}
export async function updateSubscription(callbackUrl) {
const instagram = await client();
let data = await instagram.subscriptions.list();
let activeSubscriptions = data.result;
console.log(data);
let objectSubscriptions = activeSubscriptions.filter(i => i.object === 'user' && !i.object_id && i.callback_url === callbackUrl)
if (!objectSubscriptions.length) {
// {
// result: {
// object: 'tag',
// object_id: 'hello_lol',
// aspect: 'media',
// callback_url: 'http://dev.tmshv.ru/callback/hudozka',
// type: 'subscription',
// id: '22502218'
// },
// remaining: 4988,
// limit: 5000
// }
// {
// result: {
// object: 'user',
// object_id: null,
// aspect: 'media',
// callback_url: 'http://dev.tmshv.ru/callback/hudozka',
// type: 'subscription',
// id: '22501989'
// },
// remaining: 4995,
// limit: 5000
// }
await instagram.subscriptions.subscribeUser(callbackUrl);
// let data = await instagram.subscriptions.subscribeTag('love', callbackUrl);
console.log(data);
return data;
}
}
async function client() {
if (instagramClient) return instagramClient;
@@ -47,7 +47,18 @@ export default class Subscription extends EndPoint {
}
removeAll(){
// ig.del_subscription({ all: true }, function(err, subscriptions, remaining, limit){});
const m = this.method('del_subscription');
return new Promise((resolve, reject) => {
m({all: true}, (error, result, remaining, limit) => {
if (error) return reject(error);
resolve({
result: result,
remaining: remaining,
limit: limit
});
});
});
}
remove(id){
+27 -10
View File
@@ -1,7 +1,8 @@
import {databaseUri, port} from './config'
import {databaseUri, port, updateSubscriptionDelay, updateSubscriptionCallbackUrl} from './config'
import {connect} from './core/db';
import server from './server';
import update from './core/update';
import {updateSubscription, clearSubscriptions} from './core/update';
connect(databaseUri)
.catch(error => {
@@ -14,14 +15,30 @@ connect(databaseUri)
.then(() => {
console.log(`Start listening ${port}`);
})
.then(clearSubscriptions)
.then(() => {
return update('hudozka', {
"changed_aspect": "media",
"object": "tag",
"object_id": "love",
// "time": 1458675620,
"time": 1458594000,
"subscription_id": 22487204,
"data": {}
})
let repeat = time => fn => setInterval(fn, time);
updateSubscription(updateSubscriptionCallbackUrl);
repeat(updateSubscriptionDelay)(() => {
updateSubscription(updateSubscriptionCallbackUrl);
});
});
// .then(() => {
// return update('hudozka', {
// "changed_aspect": "media",
// "object": "tag",
// "object_id": "love",
// // "time": 1458675620,
// "time": 1458594000,
// "subscription_id": 22487204,
// "data": {}
// })
// .catch(e => {
// console.log(e);
// })
// .then(result => {
// console.log('update done');
// console.log(result);
// });
// })
+3 -1
View File
@@ -1,3 +1,5 @@
import {postType} from '../config';
let date = i => new Date(parseInt(i) * 1000);
/**
@@ -61,7 +63,7 @@ let date = i => new Date(parseInt(i) * 1000);
*/
export const postFromInstagramMedia = i => ({
data: i,
type: 'instagram',
type: postType,
date: date(i['created_time']),
id: i.id
});
+1
View File
@@ -30,6 +30,7 @@ export function authCallback() {
var accessToken = client.access_token;
}
if(user) ctx.cookies.set('jwt', user.jwtToken);
ctx.status = user ? 200 : 401;
ctx.session.user = user;
ctx.session.accessToken = accessToken;
+7 -1
View File
@@ -3,6 +3,8 @@ import update from '../core/update';
export function callbackGet() {
return get('/callback/:id', async (ctx, id) => {
console.log('challenge', id);
if(ctx.query['hub.mode'] == 'subscribe'){
ctx.body = ctx.query['hub.challenge'];
}else{
@@ -14,8 +16,12 @@ export function callbackGet() {
export function callbackPost() {
return post('/callback/:id', async (ctx, id) => {
let body = ctx.request.body;
console.log(id, body);
update(id, body);
ctx.status = 200;
ctx.body = '';
//body example
// {
// "changed_aspect": "media",
@@ -5,6 +5,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';
module.exports = {
entry: './src/app.js',
watch: true,
//resolve: {
// modulesDirectories: [
// './node_modules'