Dynamically building a complex object - javascript

This will be the different for every user based on their roles. I am looking to build an object that can look like this:
let permissions = {
'state': {
'tool': ['subTool1', 'subTool2']
}
}
An example:
roles = ['NY_email_submit', 'NY_email_approve', 'NY_build_submit', 'NY_build_view', 'DC_email_submit']
let permissions = {
'NY': {
'email': ['submit', 'approve'],
'build': ['submit', 'view']
},
'DC': {
'email': ['submit']
}
};
I am looping through a list, named roles, passed in that contains strings broken up like state_tool_subTool.
I would like it to have no duplicates. For example, if the next user role ran through the loop with the object above is NY_build_approve, I would like to simply add approve to the the list at ['build'].
Currently I have this that is not working correctly.
roles.forEach(role => {
role = role.split('_');
let state = role[0];
let tool = role[1];
let subTool = role[2];
if ([state] in permissions) {
permissions[state] = { [`${tool}`]: [subTool] };
} else {
//permissions[state][`${tool}`].push(subTool);
}
});

This should do the trick! You were on the right track, just needed another layer of checks
let permissions = {};
roles = ['NY_email_submit','NY_email_approve','NY_build_submit','NY_build_view', 'DC_email_submit'];
roles.forEach(role => {
let [state, tool, subTool] = role.split('_');
if (state in permissions) {
if (tool in permissions[state]) {
permissions[state][tool].push(subTool)
} else {
permissions[state][tool] = [subTool]
}
} else {
permissions[state] = {[tool]: [subTool]}
}
});
console.log(permissions);

roles = ['NY_email_submit', 'NY_email_approve', 'NY_build_submit', 'NY_build_view', 'DC_email_submit']
let permissions = {};
roles.forEach(role => {
role = role.split('_');
let state = role[0];
let tool = role[1];
let subTool = role[2];
if (!permissions[state]) {
permissions[state] = {[tool] : [subTool]};
} else {
if (permissions[state][tool]) {
if(!permissions[state][tool].includes(subTool)) {
permissions[state][tool] = [...permissions[state][tool], subTool];
}
}
else {
permissions[state][tool] = [subTool];
}
}
});
console.log(permissions);

here is another approach using reduce
roles = ['NY_email_submit', 'NY_email_approve', 'NY_build_submit', 'NY_build_view', 'DC_email_submit']
sp=roles.map(o=>o.split("_")).reduce((acc,curr)=>{
if (!acc[curr[0]]) acc[curr[0]]={...acc[curr[0]],[curr[1]]:[...[curr[2]]]}
else {
if(acc[curr[0]][curr[1]]) {
i=acc[curr[0]][curr[1]]
acc[curr[0]]={...acc[curr[0]],[curr[1]]:[...i,...[curr[2]]]} }
else {acc[curr[0]]={...acc[curr[0]],[curr[1]]:[...[curr[2]]]} }
}
return acc
},{})
console.log(sp)

Related

How to write unit test with Jasmine-Karma in Angular?

I have two functions I need to write unit test for it. I tried some test but I don't know to check whether my variable value is changing according to the condition.
ifAllowed: Boolean = false;
checkRoleModifierExists() {
if (this.userDetails && this.userDetails.roles) {
for (
let userRolesIndex = 0;
userRolesIndex < this.userDetails.roles.length;
userRolesIndex++
) {
if (this.userDetails.roles[userRolesIndex] === 'ROLE_ADMIN_SUPPORT' &&
this.roleModifiers.body &&
this.roleModifiers.body.length) {
this.ifAllowed = this.ifAllowedFun();
}
if (this.userDetails.roles[userRolesIndex] === 'ROLE_ADMIN') {
this.ifAllowed = true;
}
}
}
}
ifAllowedFun() {
let ifRole = false;
for (const roleModifier of this.roleModifiers.body) {
if (roleModifier === 'PC-ABC') {
ifRole = true;
}
}
return ifRole;
}
this is test which I tried but it's failing.
it('should check roles modifiers ', () => {
component.ifAllowed = false;
component.ngOnInit();
spyOn(component, 'checkRoleModifierExists').and.callThrough();
component.userDetails = {
roles: ''
};
component.userDetails.roles = [ 'ROLE_ADMIN_SUPPORT' ];
component.roleModifiers = {
body: [ 'PC-ABC' ]
};
component.checkRoleModifierExists();
expect(component.ifAllowed).toEqual(true);
});

How to override a owl function in odoo?

I want to override a function in companyService but have no idea how to do it.
Here is the code in company_service.js and I want to override the start function.
/** #odoo-module **/
import { browser } from "#web/core/browser/browser";
import { registry } from "#web/core/registry";
import { symmetricalDifference } from "#web/core/utils/arrays";
import { session } from "#web/session";
function parseCompanyIds(cidsFromHash) {
const cids = [];
if (typeof cidsFromHash === "string") {
cids.push(...cidsFromHash.split(",").map(Number));
} else if (typeof cidsFromHash === "number") {
cids.push(cidsFromHash);
}
return cids;
}
function computeAllowedCompanyIds(cids) {
const { user_companies } = session;
let allowedCompanyIds = cids || [];
const availableCompaniesFromSession = user_companies.allowed_companies;
const notReallyAllowedCompanies = allowedCompanyIds.filter(
(id) => !(id in availableCompaniesFromSession)
);
if (!allowedCompanyIds.length || notReallyAllowedCompanies.length) {
allowedCompanyIds = [user_companies.current_company];
}
return allowedCompanyIds;
}
export const companyService = {
dependencies: ["user", "router", "cookie"],
start(env, { user, router, cookie }) {
let cids;
if ("cids" in router.current.hash) {
cids = parseCompanyIds(router.current.hash.cids);
} else if ("cids" in cookie.current) {
cids = parseCompanyIds(cookie.current.cids);
}
let allowedCompanyIds = Object.values(session.user_companies.allowed_companies).map(company => company.id);
const stringCIds = allowedCompanyIds.join(",");
router.replaceState({ cids: stringCIds }, { lock: true });
cookie.setCookie("cids", stringCIds);
user.updateContext({ allowed_company_ids: allowedCompanyIds });
const availableCompanies = session.user_companies.allowed_companies;
return {
availableCompanies,
get allowedCompanyIds() {
return allowedCompanyIds.slice();
},
get currentCompany() {
return availableCompanies[allowedCompanyIds[0]];
},
setCompanies(mode, ...companyIds) {
// compute next company ids
let nextCompanyIds;
if (mode === "toggle") {
nextCompanyIds = symmetricalDifference(allowedCompanyIds, companyIds);
} else if (mode === "loginto") {
const companyId = companyIds[0];
if (allowedCompanyIds.length === 1) {
// 1 enabled company: stay in single company mode
nextCompanyIds = [companyId];
} else {
// multi company mode
nextCompanyIds = [
companyId,
...allowedCompanyIds.filter((id) => id !== companyId),
];
}
}
nextCompanyIds = nextCompanyIds.length ? nextCompanyIds : [companyIds[0]];
// apply them
router.pushState({ cids: nextCompanyIds }, { lock: true });
cookie.setCookie("cids", nextCompanyIds);
browser.setTimeout(() => browser.location.reload()); // history.pushState is a little async
},
};
},
};
registry.category("services").remove("company").add("company", companyService);
You can use the patch utility
However, there are situations for which it is not sufficient. In those cases, we may need to modify an object or a class in place. To achieve that, Odoo provides the utility function patch. It is mostly useful to override/update the behavior of some other component/piece of code that one does not control.
Example:
/** #odoo-module **/
import { patch } from "#web/core/utils/patch";
import { companyService } from "#web/webclient/company_service";
patch(companyService, 'module_name.companyService', {
start(env, { user, router, cookie }) {
return this._super(env, { user, router, cookie });
}
});

JavaScript Syntax III: Why is my code throwing undefined on the ratings?

so I am currently working on a project on Code Academy, I am not certain why is it showing undefined. Although I've watched the walk through video, the project is named Build a Library. Here's my entire code:
I am still confused regarding JavaScrip, so please bear with me. Thank you for those who will answer!
class Media {
constructor(title) {
this._title = title;
this._ratings = [];
this._isCheckedOut = false;
}
get title() {
return this._title;
}
get isCheckedOut() {
return this._isCheckedOut;
}
get ratings() {
return this._ratings;
}
set isCheckedOut(value) {
this._isCheckedOut = value;
}
toggleCheckOutStatus() {
this._isCheckedOut = !this._isCheckedOut;
}
getAverageRating() {
let ratingsSum = this.ratings.reduce((accumulator, rating) => accumulator + rating);
}
addRating(value) {
this.ratings.push(value);
}
}
class Book extends Media {
constructor(author, title, pages) {
super(title);
this._author = author;
this._pages = pages;
}
get author() {
return this._author;
}
get pages() {
return this._pages;
}
}
class Movie extends Media {
constructor(director, title, runTime) {
super(title);
this._director = director;
this._runTime = runTime;
}
get director() {
return this._director;
}
get runTime() {
return this._runTime;
}
}
const historyOfEverything = new Book("Bill Bryson", "A Short History of Nearly Everything", 544);
historyOfEverything.toggleCheckOutStatus();
console.log(historyOfEverything.isCheckedOut);
historyOfEverything.addRating(4);
historyOfEverything.addRating(5);
historyOfEverything.addRating(5);
console.log(historyOfEverything.getAverageRating());
const speed = new Movie("Jan de Bont", "Speed", 116);
speed.toggleCheckOutStatus();
console.log(speed.isCheckedOut);
speed.addRating(1);
speed.addRating(1);
speed.addRating(5);
console.log(speed.getAverageRating());
because you are not returning anything from the getAverageRating function,
you should add : return ratingsSum/this.ratings.length if i understood what you want to do , so the whole function will be something like this:
getAverageRating() {
let ratingsSum = this.ratings.reduce(
(accumulator, rating) => accumulator + rating
);
return ratingsSum/this.ratings.length
}

Why can't I refactor those accumulating ifs by using a jump table?

I try to do a minor refactoring, but it breaks all tests.
I have a lot of ifs that I'd like to get rid off by using a jump table.
I want to go from here :
export class Pharmacy {
constructor(drugs = []) {
this.drugs = drugs
}
updatePharmacyBenefits() {
this.drugs.forEach((drug) => {
if (drug.name !== 'Magic Pill')
drug.setBenefitStrategy(new MagicPillStrategy())
if (drug.name === 'Herbal Tea')
drug.setBenefitStrategy(new HerbalTeaStrategy())
if (drug.name === 'Fervex')
drug.setBenefitStrategy(new FervexStrategy())
if (drug.name === 'Dafalgan')
drug.setBenefitStrategy(new DafalganStrategy())
drug.updateBenefit()
drug.updateExpiration()
})
return this.drugs
}
}
to here :
export class Pharmacy {
constructor(drugs = []) {
this.drugs = drugs
}
updatePharmacyBenefits() {
const drugStrategies = {
'Herbal Tea': new HerbalTeaStrategy(),
'Magic Pill': new MagicPillStrategy(),
Fervex: new FervexStrategy(),
Dafalgan: new DafalganStrategy(),
}
const specialsDrugs = ['Herbal Tea', 'Fervex', 'Magic Pill', 'Dafalgan']
this.drugs.forEach((drug) => {
if (drug.name.includes(specialsDrugs))
drug.setBenefitStrategy(drugStrategies[drug.name])
drug.updateBenefit()
drug.updateExpiration()
})
return this.drugs
}
}
I have no meaningful errors messages, I can just observe all my tests failing has if nothing has happened.

filter array to product check in record for events

I have an activity feed, it contains a number of different types of activity for our site.
one type of activity is checkin. which logs when a user checks in and checkouts of a site.
The record entries look like so
Entryable_id | Entry_type | Action | timestamp
1 Ticket Update 12:01
3 Ticket New 12:07
4 CheckIn ClockedIn 14:30
4 CheckIn ClockedOut 17:30
What I want to do is create an array with entries in it like so
Entryable_id | ClockedIn| ClockedOut
4 14:30 17:30
so far what I have is
{
let staffCheckins = []
let checkinRecord = []
if (this.DiaryStore.entries.length) {
this.DiaryStore.entries.forEach(function(val) {
if (val.entryable_type === 'CheckIn') {
staffCheckins.push(val);
return val
}
})
}
staffCheckins.forEach(function(val) {
if (val.action === "ClockedIn") {
checkinRecord[val.entryable_id] = {
clockedIn: val.created_at,
user: val.user
}
}
if (val.action === "ClockedOut") {
checkinRecord[val.entryable_id] = {
clockedOut: val.created_at
}
}
})
console.log(completeCheckin)
},
which gives
1: clockedIn: "2019-07-22T10:26:45.000000Z",
2: clockedIn: "2019-07-22T12:38:02.000000Z"
so I assume that it is not appending to the key when i do
checkinRecord[val.entryable_id] = {clockedOut: val.created_at}
On top of that this all feels like a mess. is there a better way to filter and get what I need?
Thanks
You need to merge attribute, instead of assign to new object
staffCheckins.forEach(function(val) {
if (!checkinRecord[val.entryable_id]) {
checkinRecord[val.entryable_id] = {}
}
if (val.action === "ClockedIn") {
checkinRecord[val.entryable_id] = {
...checkinRecord[val.entryable_id],
clockedIn: val.created_at,
user: val.user
}
} else (val.action === "ClockedOut") {
checkinRecord[val.entryable_id] = {
...checkinRecord[val.entryable_id],
clockedOut: val.created_at
}
}
}
so I haven't gotten to test it because I'm out and about but you could try something like this. If they object entryable_id doesnt exist in the current object in the array, then it will create a new object with the members, otherwise it will find the object and update the fields
{
let staffCheckins = [];
let checkinRecord = [];
if (this.DiaryStore.entries.length) {
staffCheckins = this.DiaryStore.filter(val => val.entryable_type.toLowerCase() === 'checkin');
}
staffCheckins.forEach(function(val, i) {
let { action, entryable_id, created_at, user } = val;
if (!entryable_id in checkinRecord[i]) {
checkinRecord[i] = {
clockedIn: created_at,
clockedOut: created_at,
user
}
}
if (action.toLowerCase() === 'clockedin') {
checkinRecord[i] = {
...checkinRecord[i],
clockedIn: created_at,
user
}
} else if (action.toLowerCase() === 'clockedout') {
checkinRecord[i] = {
...checkinRecord[i],
clockedOut: created_at
}
}
});
}
apologies if I understood wrong but I'm also no currently at my actual computer to test any of it
You could do this whole operation in a filter reduce combination and create a groupBy object using the Entryable_id as keys.
Once loop completes get values array of that object
const checkinGroup = data.filter(({Entry_type}) => Entry_type === 'CheckIn')
.reduce((a, c)=>{
let {Entryable_id:id, Action, timestamp} = c;
a[id] = a[id] || {Entryable_id: id, ClockedIn: null, ClockedOut: null};
a[id][Action] = timestamp;
return a;
},{});
const res = Object.values(checkinGroup)
console.log(res)
<script>
const data = [{
Entryable_id: 1,
Entry_type: 'Ticket',
Action: 'Update',
timestamp: '12:01'
},
{
Entryable_id: 3,
Entry_type: 'Ticket',
Action: 'New',
timestamp: '12:07'
},
{
Entryable_id: 4,
Entry_type: 'CheckIn',
Action: 'ClockedIn',
timestamp: '14:30'
},
{
Entryable_id: 4,
Entry_type: 'CheckIn',
Action: 'ClockedOut',
timestamp: '17:30'
}
]
</script>

Categories

Resources