Composer-Rest-Server is generating an additional id string in my concept - hyperledger

I have defined a concept in my model file. It looks like this
concept DoctorSchedule {
o Boolean AM12to1 optional
o Boolean AM1to2 optional
o Boolean AM2to3 optional
o Boolean AM3to4 optional
o Boolean AM4to5 optional
o Boolean AM5to6 optional
o Boolean AM6to7 optional
o Boolean AM7to8 optional
o Boolean AM8to9 optional
o Boolean AM9to10 optional
o Boolean AM10to11 optional
o Boolean AM11to12 optional
o Boolean PM12to1 optional
}
participant Doctor identified by doctorID {
o String doctorID
o String contact
o DoctorSchedule doctorSchedule
}
When I test it on the composer-playground, and try to add a new doctor participant. The JSON preview looks something like this
{
"$class": "org.acme.Doctor",
"doctorID": "0624",
"contact": "",
"doctorSchedule": {
"$class": "org.acme.DoctorSchedule",
"AM12to1": false,
"AM1to2": false,
"AM2to3": false,
"AM3to4": false,
"AM4to5": false,
"AM5to6": false,
"AM6to7": false,
"AM7to8": false,
"AM8to9": false,
"AM9to10": false,
"AM10to11": false,
"AM11to12": false,
"PM12to1": false,
}}
But when I generate the composer-rest-server and try to add a doctor using the post method, an additional id field appears
{
"$class": "org.acme.Doctor",
"doctorID": "stri1ng",
"contact": "string",
"doctorSchedule": {
"$class": "org.acme.DoctorSchedule",
"AM12to1": true,
"AM1to2": true,
"AM2to3": true,
"AM3to4": true,
"AM4to5": true,
"AM5to6": true,
"AM6to7": true,
"AM7to8": true,
"AM8to9": true,
"AM9to10": true,
"AM10to11": true,
"AM11to12": true,
"PM12to1": true,
"id": "string"
}}
What is this id field inside the DoctorSchedule concept? According to my understanding, you don't need an ID to identify a concept (like with assets or participants.) And why is this id field appearing in the composer-rest-server and not on the composer-playground?
Note: The post method throws an error if this id is a blank string.

I think you have found a bug in the REST server - I have added this new issue: 3963 whilst investigating your problem I also discovered a related problem and created a 2nd issue: 3962
My experience differs from yours in that I can leave the extra id field empty - which you obviously can't do with the DoctorID.

Related

Return ONLY selected fields within a TypeORM find request

I'm struggling in returning only selected fields in my TypeORM find request.
Assuming the following request
const data = await AppDataSource.manager.find(User, {
select: {
id: true,
hash: true,
firstname: true,
lastname: false,
},
take: 10, // Just here to shrink dataset
});
The script works pretty well excepted that it return every field of my model, with default value initialized.
[
User {
prefix: 'usr',
hash: 'usr_835b0ad2-XXXXXX',
email: undefined,
accountValidated: false,
role: 'free',
myKeyOne: true,
myKeyTwo: false,
gender: 'unspecified',
lastConnexion: 2023-01-19T10:11:02.733Z,
pendingDeletion: false,
deletionDate: undefined,
firstname: 'Clément',
lastname: undefined,
password: undefined,
facebookId: undefined,
googleId: undefined,
id: 158
},
...
]
Of course, it's not usable as it, because I have extensive relations, and thus the payload would be extremely heavy.
Are you aware of a method / a way to remove all unnecessary fields ?
i.e. I'm expecting
[
User {
id: 124,
hash: 'urs_XXXX',
firstname: 'Clément',
},
...
]
In older versions of typeorm I think you need to select with an array of strings, try:
select: ["id", "hash", "firstname"],
See this older version of the docs: https://github.com/typeorm/typeorm/blob/bc60dd559ba42af083ddea17f01205c78c83c7e0/docs/find-options.md
After hours of researches I've finally found out why it behaved like this.
TypeORM relies on class definitions and typescript so...
if you have typescript default values OR if you have rewrite your constructor, all the "default" properties are injected.
Assuming a User model
❌ You should not do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
#Column({ name: 'account_validated', nullable: false})
accountValidated?: boolean = false
//Your other fields...
}
✅ You should do
#Entity({ name: 'users' })
class User {
#Column()
firstname?: string;
#Column({ nullable: true })
lastname?: string;
#Column({ unique: true, nullable: false })
email!: string;
// Use default argument of the decorator
#Column({ name: 'account_validated', nullable: false, default: false})
accountValidated?: boolean
//Your other fields...
}
And if you need in some way to init a default, then create a public static method which return the Entity instead of using the constructor.
#Entity({ name: 'users' })
class User {
//...fields
public static init(...params): User {
let _user = new User()
//...populate your object
return _user
}
}

How to use nested maps in Dart?

I am trying to use Dart alongside a api for a school system i have reverse engineered and I'm trying to implement it in a library, when using dio to send a request it is converted to a map (the output of the api is json i think) but it is nested and I’m not sure on how to work with them.
This is the code i have written
class StudentClient{
String sessionID;
StudentClient(this.sessionID);
Future<Map> basicInfo() async {
var dio = Dio();
dio.options.headers["Authorization"] = "Basic $sessionID";
Response loginRequest = await dio.get(
'https://www.classcharts.com/apiv2student/ping',
options: Options(contentType: Headers.formUrlEncodedContentType),
);
assert(loginRequest.data is Map);
Map<dynamic, dynamic> request = loginRequest.data;
return request;
}
and the (censored) output
{success: 1, data: {user: {id: 696969, name: Foo Bar, first_name: Foo, last_name: Bar, avatar_url: https://asdsdsdsd/26.0.0/img/faces/default.png, display_behaviour: true, display_parent_behaviour: false, display_homework: true, display_rewards: true, display_detentions: true, display_report_cards: true, display_classes: false, display_announcements: true, display_attendance: false, display_attendance_type: none, display_attendance_percentage: true, display_activity: true, display_mental_health: false, display_mental_health_no_tracker: false, display_timetable: true, is_disabled: false, display_two_way_communications: true, display_absences: false, can_upload_attachments: false, display_event_badges: false, display_avatars: false, display_concern_submission: false, display_custom_fields: false, pupil_concerns_help_text: , allow_pupils_add_timetable_notes: false, detention_alias_plural_uc: Detentions, announcements_count: 0, messages_count: 0, pusher_channel_name: Pupil_dfghfghhghfghfghfghfghfghfghfghfghfgh, has_birthday: true, has_new_survey: false, survey_id: null}}, meta: {version: 26.0.0}}
Any help would be appreciated!

Flutter How To Update/Add Value to a Key in a Map<K,V>

Currently I have a map that looks like this to send emails via an API:
Map body = {"personalizations": [
{
"to": [
{
"email": "$receiverEmail"
}
],
"dynamic_template_data": {
"EmployeeName": "$employeeName",
"EmployeeID": "$employeeID",
"PatientName": "$patientName",
"ProviderName": "$providerName",
"TreatmentDate": "$treatmentDate",
"Diagnosis": "$diagnosis"
}
}
],
"from": {
"email": "$userEmail"
},
"template_id": "$templateID"
};
I am planning to use this structure with 2 forms of emails and for that to happen I need to update/add values under the dynamic_template_data key.
Therefore I am trying to find out how I could update/add value to that specific key. I found a function called Map.update() but I am unsure as how to properly use it. How do I approach this problem?
Just assign a new value to a specific key to update.
body['personalizations'][0]['dynamic_template_data']['EmployeeName'] = 'John Doe';
or
body['personalizations'][0]['dynamic_template_data']['Salary'] = 5000.00;
another example to do an assignment only if it doesn't exist yet
(body['personalizations'][0] as Map).putIfAbsent('Salary', () => 5000.00);
Map.update() and Map.updateAll() is a predefined function for this.
Map<String, bool> filterMap = {
'All': true,
'Open': false,
'Inprocess': false,
'Resolved': false,
'Closed': false,
};
just use this to set all value pairs to false :-
filterMap.updateAll((key, value) => value = false);
OUTPUT :
[MapEntry(All: false), MapEntry(Open: false), MapEntry(Inprocess: false), MapEntry(Resolved: false), MapEntry(Closed: false)]
In case you want to change a single value :-
filterMap.update(filterMap.keys.toList()[index]),(value) => value = true);
(filterMap.keys.toList()[index]) -> this is key name. I have used it in list. So, to find a element on which user tapped, I have used this. You can give a key name there.
filterMap.update('Open'),(value) => value = true);
OUTPUT :
[MapEntry(All: false), MapEntry(Open: true), MapEntry(Inprocess: false), MapEntry(Resolved: false), MapEntry(Closed: false)]

D2L How to create forum topic using Rest API?

Using D2L Rest API Sending following block for creating topic inside already existing forum:
URL: POST /d2l/api/le/(D2LVERSION: version)/(D2LID: orgUnitId)/discussions/forums/(D2LID: forumId)/topics/
{
"Name" : "Test Forum API",
"Description" : {
"Text" : "",
"Html" : "Test"
},
"AllowAnonymousPosts" : true,
"StartDate" : null,
"EndDate" : null,
"IsHidden" : false,
"UnlockStartDate" : null,
"UnlockEndDate" : null,
"RequiresApproval" : false,
"ScoreOutOf" : null,
"IsAutoScore" : true,
"IncludeNonScoredValues" : true,
"ScoringType" : null,
"IsLocked" : false,
"MustPostToParticipate" : true
}
Getting error:
INFO: Redirect requested but followRedirects is disabled
Status Code 302 Object moved to /d2l/error/404
Post and Redirect don't work together. Often environments (a loadbalancer or other network component) will automatically redirect all http operations to https. Then your client library won't actually follow the 302.
You probably want to use https if it is enabled, and you can make the D2L Libraries produce https urls.
(You may also want to have your client http library you are using follow redirects though because there are scenarios where the GET operations might get redirected)
Note that the CreateTopicData structure that you must pass the API to create a new topic does not use a RichText composite structure for the Description property on input. Instead, you must use a RichTextInput composite structure, which is slightly different:
{
"Name" : "Test Forum API",
"Description" : {
"Content" : "Test",
"Type": "HTML"
},
...
}
The API will pass back a RichText structure on output, however.
Using our test service, with a POST to an URL like this (assuming an org ID of 8083, and a forum ID of 4174)
https://myLMShost.edu/d2l/api/le/1.0/8083/discussions/forums/4174/topics/
we passed in a JSON structure that looks like this:
{'AllowAnonymousPosts': True,
'Description': {'Content': 'test', 'Type': 'HTML'},
'EndDate': None,
'IncludeNonScoredValues': False,
'IsAutoScore': True,
'IsHidden': False,
'IsLocked': False,
'MustPostToParticipate': True,
'Name': 'Test Forum API',
'RequiresApproval': False,
'ScoreOutOf': None,
'ScoringType': None,
'StartDate': None,
'UnlockEndDate': None,
'UnlockStartDate': None}
And our test service returned the new topic post, like this:
{'AllowAnonymousPosts': True,
'Description': {'Html': 'test', 'Text': ''},
'EndDate': None,
'ForumId': 4174,
'IncludeNonScoredValues': False,
'IsAutoScore': True,
'IsHidden': False,
'IsLocked': False,
'MustPostToParticipate': True,
'Name': 'Test Forum API',
'PinnedPostCount': 0,
'RatingsCount': 0,
'RatingsSum': 0,
'RequiresApproval': False,
'ScoreOutOf': None,
'ScoredCount': 0,
'ScoringType': None,
'StartDate': None,
'TopicId': 88569,
'UnapprovedPostCount': 0,
'UnlockEndDate': None,
'UnlockStartDate': None}

Propel archivable behavior doesn't work properly (archived_at column doesn't get updated on insert)

I have some problems with the Propel's archivable behavior. For some reasons, Propel doesn't set archived_at field to the current datetime when the object is being archived.
My schema:
SeminarCustomer:
tableName: seminar_customer
columns:
id: { type: integer, required: true, primaryKey: true, foreignClass: Customer, foreignReference: id, onDelete: cascade }
...
office_id: { type: integer, required: false, foreignTable: office, foreignReference: id }
entity_id: { type: integer, required: true, default: 1 }
propel_behaviors:
timestampable: ~
archivable: ~
SeminarCustomer::archive method:
public function archive(PropelPDO $con = null)
{
if ($this->isNew()) {
throw new PropelException('New objects cannot be archived. You must save the current object before calling archive().');
}
if (!$archive = $this->getArchive($con)) {
$archive = new SeminarCustomerArchive();
$archive->setPrimaryKey($this->getPrimaryKey());
}
$this->copyInto($archive, $deepCopy = false, $makeNew = false);
// NOTE: here should be $archive->setArchivedAt(time());
$archive->save($con);
return $archive;
}
archived_at column definitely exists in my seminar_customer_archive table.
Does anybody know what I am doing wrong ? Or maybe there is an error in the schema?
Symfony: 1.4.17-DEV
Propel: 1.6.3
Thanks in advance!
can you force the log_archived_at parameter of the Archivable behavior? It should work out of the box...
If it can helps, here is the documentation: http://www.propelorm.org/behaviors/archivable.html
EDIT: Fixed by PR #310

Resources