Skip to main content

Account Admin

Now, it's time to implement our server to support Account Admin access, in this step, we'll continue extend our server based on Account Admin APIs to FETCH and CREATE the data of ACC Projects and Users:

Projects & Users

First, let's add a couple of helper methods for getting and importing projects and users:

First, let's include the Account Admin SDK, add the @aps_sdk/account-admin library, and also create an instance of SDK client of AdminClient at the beginning of services/aps.js file:

services/aps.js
const { SdkManagerBuilder } = require('@aps_sdk/autodesk-sdkmanager');
const { AuthenticationClient, Scopes, ResponseType } = require('@aps_sdk/authentication');
const { DataManagementClient } = require('@aps_sdk/data-management');
const { AdminClient } = require('@aps_sdk/construction-account-admin');
const { APS_CLIENT_ID, APS_CLIENT_SECRET, APS_CALLBACK_URL } = require('../config.js');

const service = module.exports = {};

const sdk = SdkManagerBuilder.create().build();
const authenticationClient = new AuthenticationClient(sdk);
const dataManagementClient = new DataManagementClient(sdk);
const adminClient = new AdminClient(sdk);

Now append the following code to the end of the services/aps.js file to support export & import projects and users:

services/aps.js
// ACC Admin APIs
service.getProjectsACC = async (accountId, token) => {
let allProjects = [];
let offset = 0;
let totalResults = 0;
do {
const resp = await adminClient.getProjects(token, accountId, {offset:offset});
allProjects = allProjects.concat(resp.results);
offset += resp.pagination.limit;
totalResults = resp.pagination.totalResults;
} while (offset < totalResults)
return allProjects;
};

service.createProjectACC = async (accountId, projectInfo, token) =>{
const resp = await adminClient.createProject( token, accountId, projectInfo );
return resp;
}

service.getProjectACC = async (projectId, token) => {
const resp = await adminClient.getProject( token, projectId );
return resp;
};

service.getProjectUsersACC = async (projectId, token) => {
let allUsers = [];
let offset = 0;
let totalResults = 0;
do{
const resp = await adminClient.getProjectUsers( token, projectId, {offset:offset});
allUsers = allUsers.concat(resp.results);
offset += resp.pagination.limit;
totalResults = resp.pagination.totalResults;
}while (offset < totalResults)
return allUsers;
};

service.addProjectAdminACC = async (projectId, email, token) => {
const userBody = {
"email": email,
"products": [{
"key": "projectAdministration",
"access": "administrator"
}, {
"key": "docs",
"access": "administrator"
}]
}
const resp = await adminClient.assignProjectUser( token, projectId, userBody );
return resp;
}

service.importProjectUsersACC = async (projectId, projectUsers, token) => {
const resp = await adminClient.importProjectUsers( token, projectId, projectUsers )
return resp;
}
tip

The method adminClient.getProjects() returns all the production projects within this hub, it's different from the Data Management GET Projects API which only returns these projects the current user is involved.

Server endpoints

Next, let's expose the new functionality to the client-side code through another set of endpoints.

Create a admin.js file under the routes subfolder with the following content:

routes/admin.js
const express = require('express');
var bodyParser = require('body-parser');

const { authRefreshMiddleware, getProjectsACC, getProjectACC, getProjectUsersACC, createProjectACC, importProjectUsersACC, addProjectAdminACC, getUserProfile } = require('../services/aps.js');

let router = express.Router();

router.use(authRefreshMiddleware);

router.get('/api/admin/projects', async function(req, res, next){
try {
const projects = await getProjectsACC( req.query.accountId, req.oAuthToken.access_token);
res.json(projects);
} catch (err) {
next(err);
}
});

router.get('/api/admin/project', async function(req, res, next){
let projectsList = [];
try {
const projectInfo = await getProjectACC( req.query.projectId, req.oAuthToken.access_token);
projectsList.push(projectInfo);
res.json(projectsList);
} catch (err) {
next(err);
}
});

router.post('/api/admin/projects', bodyParser.json(), async function (req, res, next) {
const accountId = req.body.accountId;
const projects = req.body.data;
let projectsCreated = [];
let projectsFailed = [];
await Promise.all(
projects.map(async (project) => {
try{
let projectInfo = await createProjectACC(accountId, project, req.oAuthToken.access_token);
projectsCreated.push(projectInfo.name);
while( projectInfo.status != "active" ){
function delay(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
await delay(1000);
projectInfo = await getProjectACC( projectInfo.id, req.oAuthToken.access_token);
}
const profile = await getUserProfile(req.oAuthToken);
await addProjectAdminACC( projectInfo.id, profile.email, req.oAuthToken.access_token )
}catch(err){
console.warn("Failed to create project for: "+ project.name + " due to: "+ err.message )
projectsFailed.push( project.name )
}
})
)
res.json({'Succeed':projectsCreated, 'Failed': projectsFailed });
});

router.get('/api/admin/project/users', async function (req, res, next) {
try {
const users = await getProjectUsersACC(req.query.projectId, req.oAuthToken.access_token);
res.json(users);
} catch (err) {
next(err);
}
});

router.post('/api/admin/project/users', bodyParser.json(), async function (req, res, next) {
const projectId = req.body.projectId;
const users = {
'users': req.body.data
};
try {
const usersRes = await importProjectUsersACC(projectId, users, req.oAuthToken.access_token);
res.json(usersRes);
} catch (err) {
next(err);
}
});

module.exports = router;

And mount the router to our server application by modifying server.js:

server.js
const express = require('express');
const session = require('cookie-session');
const { PORT, SERVER_SESSION_SECRET } = require('./config.js');

let app = express();
app.use(express.static('wwwroot'));
app.use(session({ secret: SERVER_SESSION_SECRET, maxAge: 24 * 60 * 60 * 1000 }));
app.use(require('./routes/auth.js'));
app.use(require('./routes/hubs.js'));
app.use(require('./routes/admin.js'));
app.listen(PORT, () => console.log(`Server listening on port ${PORT}...`));

Try it out

And that's it for the server side. Time to try it out!

Start (or restart) the app from Visual Studio Code as usual,

  • Use the ID(removing b.) of one ACC hub as you get in previous step in the address: http://localhost:8080/api/admin/projects?accountId={your-account-id}. In this case the server application should respond with a JSON list of all projects available under the specified hub.
  • Use the project ID as you get in previous step, try to call the address: http://localhost:8080/api/admin/project/users?projectId={your-project-id}, the server application should respond with a JSON list of all the users from this project.
info

You may get different project list by the 2 differnt endpoints, here are the explain:

  • With Data Management API, it will return all the projects that the current user is involved.
  • With Account Admin API, it will return all the projects in the account if the current user is Account Admin.

Account Admin Response