I want to get participant model inside controller, but I only have identity/fingerprint....
The question is how to get the participant model?
the answer is use the identity/fingerprint with a rich couchdb query.
inside controller use this.sender to get fingerprint ex B5:38:A3:84:02:D1:EE:2B:CD:25:27:66:C0:F6:9E:4F:91:16:21:EE
next, first create the worldstate query, and test it in fauxton
query
{
"selector": {
"type": "io.worldsibu.examples.participant",
"identities": {
"$elemMatch": {
"fingerprint": "B5:38:A3:84:02:D1:EE:2B:CD:25:27:66:C0:F6:9E:4F:91:16:21:EE",
"status": true
}
}
}
}
done with query
now create a utils.ts to be shared in controllers like
packages/person-cc/src/utils.ts
import { appConstants as c } from '#convector-rest-sample/common';
import * as bcrypt from 'bcrypt';
import { Participant } from 'participant-cc';
const bcryptSaltRounds: number = 10;
export const hashPassword = (password: string): string => {
return bcrypt.hashSync(password, bcryptSaltRounds);
};
/**
* get Participant by Identity/Fingerprint
*/
export const getParticipantByIdentity = async (fingerprint: string): Promise<Participant> => {
const participant: Participant | Participant[] = await Participant.query(Participant, {
selector: {
type: c.CONVECTOR_MODEL_PATH_PARTICIPANT,
identities: {
$elemMatch: {
fingerprint,
status: true
}
}
}
});
if (!!participant && !participant[0].id) {
throw new Error('Cant find a participant with that fingerprint');
}
return participant[0];
}
now use it in one controller
...
import { getParticipantByIdentity, hashPassword } from './utils';
#Controller('person')
export class PersonController extends ConvectorController<ChaincodeTx> {
#Invokable()
public async create(
#Param(Person)
person: Person
) {
// get host participant from fingerprint
const participant: Participant = await getParticipantByIdentity(this.sender);
if (!!participant && !participant.id) {
throw new Error('There is no participant with that identity');
}
...
done, now deploy chaincode and test with
npx hurl invoke $CC person_create "{\"id\":\"1-100-100\",\"firstname\":\"Pete\",\"lastname\":\"Doe\",\"username\":\"peter\",\"password\":\"12345678\",\"email\":\"pete.doe#example.com\"}" -u admin
check couchdb
{
"_id": "1-100-100",
"_rev": "1-2b08d163d01dcfa5b9e9dc31bcc3b50c",
"email": "pete.doe#example.com",
"firstname": "Pete",
"id": "1-100-103",
"lastname": "Doe",
"participant": {
"id": "gov",
"identities": [
{
"fingerprint": "B5:38:A3:84:02:D1:EE:2B:CD:25:27:66:C0:F6:9E:4F:91:16:21:EE",
"status": true
}
],
"msp": "org1MSP",
"name": "Big Government",
"type": "io.worldsibu.examples.participant"
},
"password": "$2b$10$IYsgUSb/RA6zr4tT3u10HugCrxJH2loLsVUKjTkTiAAj3yewnR2SO",
"roles": [
"USER"
],
"type": "io.worldsibu.examples.person",
"username": "peter",
"~version": "\u0000CgMBDgA="
}
done
Related
I need to build a tree like structure using data from an API.
The structure i start with is as follows:
{
"type": "group",
"id": 1,
"name": "rootGroup",
"members": [],
}
There will always be a root group as the base of the tree.
I have a function named getMembersInGroup(groupId) which is an API call and returns something like:
[
{
"type": "group",
"id": 77,
"name": "IT group",
},
{
"type": "user",
"id": 40,
"name": "John"
}
]
Members can either be of type user or another group. So a user would look like:
{
"type": "user",
"id": 40,
"name": "John"
}
If it's another group it needs to recursively fetch those until there are only users or empty array left in members.
Any group can have users at any level with the tree.
A mock of getMembersInGroup:
const getMembersInGroup = async (groupId) => {
try {
const members = await fetch.callApi('/groups/' + groupId + '/members');
if (members) {
return members;
}
else {
return [];
}
} catch (error) {
return { error };
}
}
The end result should look like this:
{
"type": "group",
"id": 1,
"name": "rootGroup",
"members": [
{
"type": "group",
"id": 88,
"name": "Some group",
"members": [
{
"type": "user",
"id": 231,
"name": "SALLY"
},
{
"type": "user",
"id": 232,
"name": "Henry"
}
]
},
{
"type": "user",
"id": 41,
"name": "Chris"
}
],
}
I need help with the algorithm to create the tree.
Your getMembersInGroup function could look like this:
const getMembersInGroup = async (groupId) => {
const members = (await fetch.callApi(`/groups/${groupId}/members`)) ?? [];
for (const member of members) {
if (member.type == "group") {
member.members = await getMembersInGroup(member.id);
}
}
return members;
}
Call it like this:
async function loadTree() {
return {
type: "group",
id: 1,
name: "rootGroup",
members: await getMembersInGroup(1)
};
}
loadTree().then(result =>
console.log(result);
// Work with the result ...
).catch(error =>
console.log("error: ", error)
);
Demo with a mock implementation of fetch.callApi:
// Mock for fetch.callApi
const fetch = {
mockData: [0,[2,3,4],[5,6,7],[8,9],0,0,0,[10],0,0,[11,12],0,0],
callApi(url) {
return new Promise((resolve, reject) => {
const groupId = +url.split("/")[2];
const children = this.mockData[groupId];
if (!children) return reject("not found: " + groupId);
const result = children.map(id => {
const type = this.mockData[id] ? "group" : "user";
return {type, id, name: type + "_" + id};
});
setTimeout(() => resolve(result), 50);
});
}
}
async function loadTree() {
return {
type: "group",
id: 1,
name: "rootGroup",
members: await getMembersInGroup(1)
};
}
const getMembersInGroup = async (groupId) => {
const members = (await fetch.callApi('/groups/' + groupId + '/members')) ?? [];
for (const member of members) {
if (member.type == "group") {
member.members = await getMembersInGroup(member.id);
}
}
return members;
}
loadTree().then(result =>
console.log(JSON.stringify(result, null, 2))
).catch(error =>
console.log("error: ", error)
);
You can do something like:
const getMembersInGroup = async (groupId) => {
try {
const members = await fetch.callApi('/groups/' + groupId + '/members');
if (members) {
foreach(member in members) {
if (member.type == 'groups') {
member.members = getMembersInGroup(member.groupid)
}
}
return members;
}
else {
return [];
}
} catch (error) {
return { error };
}
}
So you have the recursion only if it's a group type, otherwise the member is returned as is.
I have created a separate service for the user that creates a simple user without any specification. Then i am using the create function from userService in AuthService for signup. In the userService, it returns the data as mongoose Schema. While in AuthService, i want to exclude password and some other details so i have created Dto for signupResponse. The problem here is that it is returning full document instead of the required properties here.
The code for userService.ts:
import {Model} from 'mongoose';
import {InjectModel} from '#nestjs/mongoose';
import {User, UserDocument} from './schemas/user.schema';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
#Injectable()
export class UserService {
constructor(#InjectModel(User.name) private userRepository: Model<UserDocument>) {}
async create(createUserDto: CreateUserDto): Promise<User> {
const newUser = new this.userRepository(createUserDto);
return await newUser.save();
}
}
the authService.ts class:
import { CreateUserDto } from 'src/user/dto/create-user.dto';
import { UserService } from 'src/user/user.service';
import { SigninDto } from './dto/signin/signin.dto';
import {JwtService} from '#nestjs/jwt';
import * as bcrypt from 'bcrypt';
import {signupResponseDto} from './dto/signup/signup-response.dto';
#Injectable()
export class AuthService {
constructor(private readonly userService: UserService, private readonly jwtService: JwtService){}
async signup(signupDto: CreateUserDto): Promise<signupResponseDto>
{
const {password, ...otherData} = signupDto;
const hashedPassword = await this.createHash(password);
const newSignupBody: CreateUserDto = {password: hashedPassword, ...otherData};
const createUser = await this.userService.create(newSignupBody);
const {username} = createUser;
const token = this.createToken(username, createUser['_id']);
const result:signupResponseDto = {_id: createUser['_id'], token, ...createUser};
return result;
}
}
The result of the api test is:
{
"_id": "60b95077448c29067c1fb349",
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1271738373jffghdfghiOjE2MjI4NDM4OTV9._HKhNMeobCm0G6B2r7aaiTDsk53Qmp36poLG4bmPmlY",
"$__": {
"strictMode": true,
"inserting": true,
"getters": {},
"_id": "60b95077448c29067c1fb349",
"wasPopulated": false,
"activePaths": {
"paths": {
"email": "require",
"username": "require",
"password": "require"
},
"states": {
"ignore": {},
"default": {},
"init": {},
"modify": {},
"require": {
"email": true,
"username": true,
"password": true
}
},
"stateNames": [
"require",
"modify",
"init",
"default",
"ignore"
]
},
"pathsToScopes": {},
"cachedRequired": {},
"session": null,
"$setCalled": {},
"emitter": {
"_events": {},
"_eventsCount": 0,
"_maxListeners": 0
},
"$options": {
"defaults": true
},
"validating": null,
"backup": {
"activePaths": {
"modify": {
"password": true,
"email": true,
"username": true,
"security_answer": true
},
"default": {
"updated_at": true,
"created_at": true,
"_id": true
}
}
},
"savedState": {}
},
"isNew": false,
"$locals": {},
"$op": null,
"_doc": {
"updated_at": "2021-06-03T21:58:11.071Z",
"created_at": "2021-06-03T21:58:11.071Z",
"_id": "60b95077448c29067c1fb349",
"password": "$2b$10$K2gq31/Bv4tythgdWx/ObigM9izspn7wd01BUKcJ2P8dORC2loW",
"email": "test#gmail.com",
"username": "test",
"security_answer": "banana",
"__v": 0
}
}
SignupDto
export class signupResponseDto
{
_id: string;
username: string;
email: string;
token: string;
created_at: Date
}
Today I'm trying to make a json data to link discord account to another account (League of Legends, Dota, etc...)
To make my database, I'm using this code:
message.reply(`Your account is link to **${args[1]}**`).then(msg => {
msg.delete({
timeout: 5000
});
});
userID = message.author;
let link = require('../link.json')
link.userID = {
name: `${message.author.username}`,
lol: `${args[1]}`,
}
var string = JSON.stringify(link, null, '\t');
fs.writeFile('./link.json', string, function(err) {
if (err) return console.error(err);
})
If bob writes /link lol boby02 and I (StarKleey 帅哥) write /link lol StarKleey the json will be:
{
"userID": { //here I would like "#<565465478767545>": {
"name": "bob",
"lol": "boby02"
},
"userID": { //and here "#<456465574385735>": {
"name": "StarKleey 帅哥",
"lol": "StarKleey"
}
}
How can I do that?
This is what I'm currently using:
link.message.author = {
name: `${message.author.username}`,
lol: `${args[1]}`,
}
Reload :
{
"#<565465478767545>": {
"name": "bob",
"lol": "boby02"
},
"#<456465574385735>": {
"name": "StarKleey 帅哥",
"lol": "StarKleey"
}
}
You're currently storing the username, while you seem to want to store the user id: you should try using User.id:
link.message.author = {
name: `${message.author.id}`,
lol: `${args[1]}`,
}
In my Node API and MongoDB, I'm trying to build an endpoint to search for data in the DB and get back the results to the client. My search goal is to show results from the Profile collection and in that way, I can build my queries to search by first name, surname, company and the combination of it as an example:
GET search?fn=joe or ?ln=doe or ?cp=Company or ?fn=...&ln=...&cp=...
Practically I can search in different ways and I can get for example all the people working for a company as a result of a search.
I would like to understand how can I achieve that with Mongoose/MongoDB and add also to the query optional a limit/pagination for the coming results.
I tried to make some simple trials but I got stuck as I do not really get it how to proceed next.
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const searchResult = await Profile.find({
$or: [
{ firstname: fn },
{ surname: ln },
{
experience: {
company: cp
}
}
]
});
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
The JSON of a profile:
{
"imageUrl": "https://i.pravatar.cc/300",
"posts": [
"5e3cacb751f4675e099cd043",
"5e3cacbf51f4675e099cd045",
"5e3cacc551f4675e099cd046"
],
"_id": "5e2c98fc3d785252ce5b5693",
"firstname": "Jakos",
"surname": "Lemi",
"email": "lemi#email.com",
"bio": "My bio bio",
"title": "Senior IT developer",
"area": "Copenhagen",
"username": "Jakos",
"experience": [
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:47:37.167Z",
"updatedAt": "2020-02-04T13:47:37.167Z",
"_id": "5e3975f95fbeec9095ff3d2f",
"role": "Developer",
"company": "Google",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-04T13:59:27.412Z",
"updatedAt": "2020-02-04T13:59:27.412Z",
"_id": "5e3978bf5e399698e20c56d4",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-09T23:00:00.000Z",
"endDate": "2019-01-05T23:00:00.000Z",
"area": "Copenhagen"
},
{
"image": "https://via.placeholder.com/150",
"createdAt": "2020-02-07T16:35:43.754Z",
"updatedAt": "2020-02-07T16:35:43.754Z",
"_id": "5e3d91dfb3a7610ec6ad8ee3",
"role": "Developer",
"company": "IBM",
"startDate": "2018-11-10T00:00:00.000Z",
"endDate": "2019-01-06T00:00:00.000Z",
"area": "Copenhagen"
}
],
"createdAt": "2020-01-25T19:37:32.727Z",
"updatedAt": "2020-02-04T23:14:37.122Z",
"__v": 0
}
The expected results are for example if I search the first name Joe I should get back all the profiles having as first name Joe. Similar for surname and company.
Please provide comments to allow me to understand if you need more scripts from the original code to see.
EDITED added the code modified of the search
// Models
const { Profile } = require("../models");
// Error handling
const { ErrorHandlers } = require("../utilities");
const SearchController = {
async getQuery(req, res) {
try {
const { fn, ln, cp } = req.query;
const query = {
$or: []
};
if (fn) query.$or.push({ firstname: fn });
if (ln) query.$or.push({ surname: ln });
if (cp) query.$or.push({ "experience.company": cp });
const searchResult = Profile.find(query, docs => {
return docs
});
if ((await searchResult).length === 0)
throw new ErrorHandlers.ErrorHandler(
404,
"Query do not provided any result"
);
res.status(200).json(searchResult);
} catch (err) {
res.status(500).json({ message: err.message });
}
}
};
module.exports = SearchController;
Have tried conditional query and modified your array search query for finding the company,
function findUser(fn, ln, cp) {
const query = {
$or: []
}
if (fn) query.$or.push({ firstname: fn })
if (ln) query.$or.push({ surname: ln })
if (cp) query.$or.push({ "experience.company": cp })
Profile.find(query, function (err, docs) {
if (err) {
console.error(err);
} else {
console.log(docs);
}
});
}
findUser("","","IBM")
I have managed to get following data through GraphQL:
{
"data": {
"city": {
"name": "Eldorado",
"users": [
{
"username": "lgraham1"
},
{
"username": "ehowell"
},
{
"username": "cbauch"
}
]
}
}
}
I have QueryType, CityType and UserType. In my QueryType I fetch city and display users by GraphQLList(UserType). What should I do if I want to display single user if there is an id provided?
My API looks like this:
all cities:
/cities/
single city:
/cities/:city_id
users for particular city:
/cities/:city_id/users
single user:
/cities/:city_id/users/:user_id
You'll need to add a user query to your main Query object.
Assuming your id is an Integer, you would do this
const Query = new GraphQLObjectType({
name: 'RootQuery',
fields: {
// ...
user: {
type: User,
args: {
id: {
type: new GraphQLNonNull(GraphQLInt)
}
},
resolve: function(rootValue, args) {
return db.users.findOne(args)
}
}
}
})
const Schema = new GraphQLSchema({
query: Query,
// ...
});
Then you can query using
{
user (id: 12345) {
...
}
}
Or you could make a function
query findUser ($id: Int!) {
user (id: $id) {
...
}
}