Remove app purchase/unpurchase
This commit is contained in:
19
src/apps.js
19
src/apps.js
@@ -1474,8 +1474,6 @@ async function install(data, auditSource) {
|
||||
if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings);
|
||||
if (addError) throw addError;
|
||||
|
||||
await purchaseApp({ appId, appstoreId: appStoreId, manifestId: manifest.id || 'customapp' });
|
||||
|
||||
const task = {
|
||||
args: { restoreConfig: null, skipDnsSetup, overwriteDns },
|
||||
values: { },
|
||||
@@ -2376,17 +2374,6 @@ async function exportApp(app, data, auditSource) {
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
async function purchaseApp(data) {
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
|
||||
const [purchaseError] = await safe(appstore.purchaseApp(data));
|
||||
if (!purchaseError) return;
|
||||
|
||||
await del(data.appId);
|
||||
|
||||
throw purchaseError;
|
||||
}
|
||||
|
||||
async function clone(app, data, user, auditSource) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
@@ -2458,8 +2445,6 @@ async function clone(app, data, user, auditSource) {
|
||||
if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings);
|
||||
if (addError) throw addError;
|
||||
|
||||
await purchaseApp({ appId: newAppId, appstoreId: app.appStoreId, manifestId: manifest.id || 'customapp' });
|
||||
|
||||
const restoreConfig = { remotePath: backupInfo.remotePath, backupFormat: backupInfo.format };
|
||||
const task = {
|
||||
args: { restoreConfig, overwriteDns, skipDnsSetup, oldManifest: null },
|
||||
@@ -2535,8 +2520,6 @@ async function unarchive(archive, data, auditSource) {
|
||||
if (addError && addError.reason === BoxError.ALREADY_EXISTS) throw getDuplicateErrorDetails(addError.message, locations, portBindings);
|
||||
if (addError) throw addError;
|
||||
|
||||
await purchaseApp({ appId, appstoreId: appStoreId, manifestId: manifest.id || 'customapp' });
|
||||
|
||||
const task = {
|
||||
args: { restoreConfig, overwriteDns },
|
||||
values: {},
|
||||
@@ -2564,8 +2547,6 @@ async function uninstall(app, auditSource) {
|
||||
const error = checkAppState(app, exports.ISTATE_PENDING_UNINSTALL);
|
||||
if (error) throw error;
|
||||
|
||||
await appstore.unpurchaseApp(appId, { appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' });
|
||||
|
||||
const task = {
|
||||
args: {},
|
||||
values: {},
|
||||
|
||||
@@ -18,9 +18,6 @@ exports = module.exports = {
|
||||
registerCloudronWithLogin,
|
||||
updateCloudron,
|
||||
|
||||
purchaseApp,
|
||||
unpurchaseApp,
|
||||
|
||||
getSubscription,
|
||||
isFreePlan,
|
||||
|
||||
@@ -171,60 +168,6 @@ function isFreePlan(subscription) {
|
||||
return !subscription || subscription.plan.id === 'free';
|
||||
}
|
||||
|
||||
// See app.js install it will create a db record first but remove it again if appstore purchase fails
|
||||
async function purchaseApp(data) {
|
||||
assert.strictEqual(typeof data, 'object'); // { appstoreId, manifestId, appId }
|
||||
assert(data.appstoreId || data.manifestId);
|
||||
assert.strictEqual(typeof data.appId, 'string');
|
||||
|
||||
const token = await settings.get(settings.APPSTORE_API_TOKEN_KEY);
|
||||
if (!token) throw new BoxError(BoxError.LICENSE_ERROR, 'Missing token');
|
||||
|
||||
const [error, response] = await safe(superagent.post(`${await getApiServerOrigin()}/api/v1/cloudronapps`)
|
||||
.send(data)
|
||||
.query({ accessToken: token })
|
||||
.timeout(60 * 1000)
|
||||
.ok(() => true));
|
||||
|
||||
if (error) throw new BoxError(BoxError.NETWORK_ERROR, error);
|
||||
if (response.status === 404) throw new BoxError(BoxError.NOT_FOUND, 'appstoreId does not exist');
|
||||
if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token');
|
||||
if (response.status === 402) throw new BoxError(BoxError.LICENSE_ERROR, response.body.message);
|
||||
// 200 if already purchased, 201 is newly purchased
|
||||
if (response.status !== 201 && response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `App purchase failed. ${response.status} ${JSON.stringify(response.body)}`);
|
||||
}
|
||||
|
||||
async function unpurchaseApp(appId, data) {
|
||||
assert.strictEqual(typeof appId, 'string');
|
||||
assert.strictEqual(typeof data, 'object'); // { appstoreId, manifestId }
|
||||
assert(data.appstoreId || data.manifestId);
|
||||
|
||||
const token = await settings.get(settings.APPSTORE_API_TOKEN_KEY);
|
||||
if (!token) throw new BoxError(BoxError.LICENSE_ERROR, 'Missing token');
|
||||
|
||||
const url = `${await getApiServerOrigin()}/api/v1/cloudronapps/${appId}`;
|
||||
|
||||
let [error, response] = await safe(superagent.get(url)
|
||||
.query({ accessToken: token })
|
||||
.timeout(60 * 1000)
|
||||
.ok(() => true));
|
||||
|
||||
if (error) throw new BoxError(BoxError.NETWORK_ERROR, error);
|
||||
if (response.status === 404) return; // was never purchased
|
||||
if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token');
|
||||
if (response.status !== 200) throw new BoxError(BoxError.EXTERNAL_ERROR, `App unpurchase failed to get app. status:${response.status}`);
|
||||
|
||||
[error, response] = await safe(superagent.del(url)
|
||||
.send(data)
|
||||
.query({ accessToken: token })
|
||||
.timeout(60 * 1000)
|
||||
.ok(() => true));
|
||||
|
||||
if (error) throw new BoxError(BoxError.NETWORK_ERROR, error);
|
||||
if (response.status === 401) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid appstore token');
|
||||
if (response.status !== 204) throw new BoxError(BoxError.EXTERNAL_ERROR, `App unpurchase failed. status:${response.status}`);
|
||||
}
|
||||
|
||||
async function getBoxUpdate(options) {
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
@@ -327,11 +270,6 @@ async function registerCloudron3(domain, version) {
|
||||
await settings.set(settings.APPSTORE_API_TOKEN_KEY, response.body.token);
|
||||
|
||||
debug(`registerCloudron: Cloudron registered with id ${response.body.id}`);
|
||||
|
||||
// // app could already have been installed if we deleted the cloudron.io record and user re-registers
|
||||
// for (const app of await apps.list()) {
|
||||
// await safe(purchaseApp({ appId: app.id, appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' }), { debug });
|
||||
// }
|
||||
}
|
||||
|
||||
async function registerCloudron(data) {
|
||||
@@ -355,11 +293,6 @@ async function registerCloudron(data) {
|
||||
await settings.set(settings.APPSTORE_API_TOKEN_KEY, response.body.cloudronToken);
|
||||
|
||||
debug(`registerCloudron: Cloudron registered with id ${response.body.cloudronId}`);
|
||||
|
||||
// app could already have been installed if we deleted the cloudron.io record and user re-registers
|
||||
for (const app of await apps.list()) {
|
||||
await safe(purchaseApp({ appId: app.id, appstoreId: app.appStoreId, manifestId: app.manifest.id || 'customapp' }), { debug });
|
||||
}
|
||||
}
|
||||
|
||||
async function updateCloudron(data) {
|
||||
|
||||
@@ -396,22 +396,8 @@ xdescribe('App API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('app install fails due to purchase failure', function (done) {
|
||||
const fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/test').reply(200, { manifest: APP_MANIFEST });
|
||||
|
||||
superagent.post(SERVER_URL + '/api/v1/apps')
|
||||
.query({ access_token: token })
|
||||
.send({ appStoreId: APP_STORE_ID, subdomain: APP_SUBDOMAIN, domain: DOMAIN_0.domain, portBindings: null, accessRestriction: null })
|
||||
.end(function (err, res) {
|
||||
expect(res.status).to.equal(402);
|
||||
expect(fake1.isDone()).to.be.ok();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('app install succeeds with purchase', async function () {
|
||||
it('app install succeeds', async function () {
|
||||
const fake1 = nock(settings.apiServerOrigin()).get('/api/v1/apps/' + APP_STORE_ID).reply(200, { manifest: APP_MANIFEST });
|
||||
const fake2 = nock(settings.apiServerOrigin()).post(function (uri) { return uri.indexOf('/api/v1/cloudronapps') >= 0; }, (body) => body.appstoreId === APP_STORE_ID && body.manifestId === APP_MANIFEST.id && body.appId).reply(201, { });
|
||||
|
||||
await settings.setAppstoreApiToken(USER_1_APPSTORE_TOKEN);
|
||||
|
||||
@@ -423,7 +409,6 @@ xdescribe('App API', function () {
|
||||
expect(res.body.id).to.be.a('string');
|
||||
APP_ID = res.body.id;
|
||||
expect(fake1.isDone()).to.be.ok();
|
||||
expect(fake2.isDone()).to.be.ok();
|
||||
taskId = res.body.taskId;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/* jslint node:true */
|
||||
/* global it:false */
|
||||
/* global describe:false */
|
||||
/* global before:false */
|
||||
/* global after:false */
|
||||
/* global beforeEach:false */
|
||||
|
||||
'use strict';
|
||||
|
||||
const appstore = require('../appstore.js'),
|
||||
common = require('./common.js'),
|
||||
expect = require('expect.js'),
|
||||
nock = require('nock');
|
||||
|
||||
const APP_ID = 'appid';
|
||||
const APPSTORE_APP_ID = 'appstoreappid';
|
||||
|
||||
describe('Appstore', function () {
|
||||
const { setup, cleanup, appstoreToken, mockApiServerOrigin } = common;
|
||||
|
||||
before(setup);
|
||||
before(() => { if (!nock.isActive()) nock.activate(); });
|
||||
after(cleanup);
|
||||
|
||||
beforeEach(nock.cleanAll);
|
||||
|
||||
it('can purchase an app', async function () {
|
||||
const scope1 = nock(mockApiServerOrigin)
|
||||
.post(`/api/v1/cloudronapps?accessToken=${appstoreToken}`, function () { return true; })
|
||||
.reply(201, {});
|
||||
|
||||
await appstore.purchaseApp({ appId: APP_ID, appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID });
|
||||
expect(scope1.isDone()).to.be.ok();
|
||||
});
|
||||
|
||||
it('unpurchase succeeds if app was never purchased', async function () {
|
||||
const scope1 = nock(mockApiServerOrigin)
|
||||
.get(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`)
|
||||
.reply(404, {});
|
||||
|
||||
const scope2 = nock(mockApiServerOrigin)
|
||||
.delete(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`, function () { return true; })
|
||||
.reply(204, {});
|
||||
|
||||
await appstore.unpurchaseApp(APP_ID, { appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID });
|
||||
expect(scope1.isDone()).to.be.ok();
|
||||
expect(scope2.isDone()).to.not.be.ok();
|
||||
});
|
||||
|
||||
it('can unpurchase an app', async function () {
|
||||
const scope1 = nock(mockApiServerOrigin)
|
||||
.get(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`)
|
||||
.reply(200, {});
|
||||
|
||||
const scope2 = nock(mockApiServerOrigin)
|
||||
.delete(`/api/v1/cloudronapps/${APP_ID}?accessToken=${appstoreToken}`, function () { return true; })
|
||||
.reply(204, {});
|
||||
|
||||
await appstore.unpurchaseApp(APP_ID, { appstoreId: APPSTORE_APP_ID, manifestId: APPSTORE_APP_ID });
|
||||
expect(scope1.isDone()).to.be.ok();
|
||||
expect(scope2.isDone()).to.be.ok();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user