TFS WorkItemRelation Attributes Object? - tfs

In reference to this document:
https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/get%20work%20item%20template?view=azure-devops-rest-4.1#workitemrelation
At the bottom of the page, the description of the WorkItemRelation is:
WorkItemRelation
+------------------------------------------------------+
+ Name + Type + Description +
+------------+--------+--------------------------------+
+------------+--------+--------------------------------+
+ attributes + object + Collection of link attributes. +
+------------+--------+--------------------------------+
+ rel + string + Relation type. +
+------------+--------+--------------------------------+
+ url + string + Link url +
+------------+--------+--------------------------------+
What is the attributes object? I can not find the definition of it. Has anyone used the TFS api enough to be familiar?

The attribute is the object type which helps us to identify the detailed properties of the workitem relationship types,
You can easily get the definition of the attributes from Work Item Relation Types API
Example:
{
"attributes": {
"usage": "workItemLink",
"editable": false,
"enabled": true,
"acyclic": true,
"directional": true,
"singleTarget": false,
"topology": "tree",
"isForward": true,
"oppositeEndReferenceName": "System.LinkTypes.Duplicate-Reverse"
},
"referenceName": "System.LinkTypes.Duplicate-Forward",
"name": "Duplicate",
"url": "https://dev.azure.com/fabrikam/_apis/wit/workItemRelationTypes/System.LinkTypes.Duplicate-Forward"
}
The Attributes consist of the following JSON elements,
usage
editable
enabled
acyclic
directional
singleTarget
topology
isForward
oppositeEndreferenceName

Related

RestAssured assertThat, wildcard for key

I have an object like this,
{
"john": {
"number": "123"
},
"sarah": {
"number": "123"
}
}
It is an object where a persons name is the key for an object, like a map.
In restAssured how can I test for a ValidatableResponse that any number whether it belongs to john or sarah matches a certain value. In this case I know there will only be one person but an "any" matcher seems appepriate here.
I have tried assertThat().body("*.number"), Matchers.is("myValue)" but it does not work and gives an error
Your problem is extracting value from a json with dynamic key (the person name, in this case). There are NO built-in functions in Rest-Assured can help you.
To solve it
you can use JsonPath jayway to extract list of number by using deep-scan feature
then use hasItem assertion of Hamcrest.
import com.jayway.jsonpath.JsonPath;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
#Test
void name() {
String json = "{\n" +
" \"john\": {\n" +
" \"number\": \"123\"\n" +
" },\n" +
" \"sarah\": {\n" +
" \"number\": \"123\"\n" +
" }\n" +
"}";
List<String> numbers = JsonPath.read(json, "$..number");
assertThat(numbers, hasItem("123"));
}
Note:
Please don't confused 2 JsonPath classes here. One is in Rest-Assured, one is in JsonPath jayway.
I have to say that I hate the json structure like this, it's better if using array to group items.
[
{
"name": "john",
"number": "123"
},
{
"name": "sarah",
"number": "123"
}
]

How to bind `$jwt.sub` on Create to property using Neo4j and GraphQL?

I'm currently using neo4j and graphql with an Apollo server.
I have the following type:
type Person {
id: ID! #id
externalId: ID
name: String!
}
extend type Person
#auth(
rules: [
{ operations: [CREATE, UPDATE], bind: { externalId: "$jwt.sub" } }
]
)
And when I try to do the following mutation:
mutation Mutation($input: [PersonCreateInput!]!) {
createPeople(input: [
{
"name": "abc"
}
]) {
people {
name
}
}
}
I get a FORBIDDEN error from Neo4j.
I debugged a bit the code, and it looks like this is what's being transformed to:
CALL {\n' +
'CREATE (this0:Person)\n' +
'SET this0.id = randomUUID()\n' +
'SET this0.name = $this0_name\n' +
'WITH this0\n' +
'CALL apoc.util.validate(NOT(this0.externalId IS NOT NULL AND this0.externalId = $this0_auth_bind0_externalId), "#neo4j/graphql/FORBIDDEN", [0])\n' +
'RETURN this0\n' +
'}\n' +
'RETURN \n' +
'this0 { .name } AS this0',
so if I understand this correctly, if externalID is NULL AND externalID is different from my jwt sub value, then it will throw the exception.
And basically what I'm trying to achieve is:
When creating a person node, assign the externalID value to the value of the sub property of my JWT.
What am I doing wrong here?
I think the double negative is causing some confusion with the predicate. The exception will be thrown if this0.externalId is null OR if this0.externalId does not equal $this0_auth_bind0_externalId due to the AND statement and surrounding NOT.
Since you're creating this this0 above it will never have this0.externalId, so this predicate will always be true and the exception will always be thrown.
I'm not strong in GraphQL, but I would think your mutation needs to set the externalId.

dymamic Schemas and nested Maps in Avro

I'm new to Avro, and am trying to write some code to serialize some nested objects.
The structure of the objects looks like this:
class Parcel {
String recipe;
Map<Integer, PluginDump> dumps;
}
class PluginDump {
byte[] state;
Map<String, Param> params;
}
class Param {
Type type; //can be e.g. StringType, BooleanType, etc
Object value;
}
So I can't use a static avro schema - each PluginDump will have a different schema depending on the types within it.
I have written some code which can generate a Schema based on an individual PluginDump.
So when serializing a Parcel, how do I 'put' each PluginDump entry?
Here is my code:
Schema parcelSchema = AvroHelper.getSchema(p);
GenericRecord parcelRecord = new GenericData.Record(parcelSchema);
parcelRecord.put("recipe", p.getRecipe().toJson());
for (Map.Entry<Integer, PluginDump> entry : p.getDumps().entrySet()) {
PluginDump dump = entry.getValue();
Integer uid = entry.getKey();
Schema dumpSchema = AvroHelper.getSchema(dump);//will be different for each PluginDump
parcelRecord.put(????
Any ideas?
I have a feeling my approach is wrong, but I can't find any examples in the documentation of dynamic schema generation or nested maps.
1 When you get GenericRecord parcelRecord = new GenericData.Record(parcelSchema); you have two fields in your record: recipe and dumps, so you can't iterate through the dumps, you must put prepared map with dumps in the second field of record, just like you did it for recipe: parcelRecord.put("dumps", dumps);. But in this case, you'll get ClassCastException, because PluginDump cannot be cast to org.apache.avro.generic.IndexedRecord, so you need to put in parcelRecord a Map of GenericRecords. Also you need this for Map<String, Param> params, cause Param cannot be cast to IndexedRecord too.
2 Then, I think that its better to use Lists instead of Maps, cause avro not very good enough to work with Maps with different types of keys and values.
3 About the Param class: if you will use auto-generated schema, Param class will be presented like this.
"type": "record",
"name": "Param",
"fields": [
{
"name": "type",
"type": {
"type": "record",
"name": "Type",
"namespace": "java.lang.reflect",
"fields": []
}
},
{
"name": "value",
"type": {
"type": "record",
"name": "Object",
"namespace": "java.lang",
"fields": []
}
}
]
As far as avro uses java.lang.reflect, you will lose type field after deserialization, avro will not know what type it was.
If you want to generate avro-schema manually for each Param, considering its type, you can do something like this (I used ClassUtils.getClass from apache commons-lang3, cause standart Class.forName method doesn't always work properly):
public Schema getParamSchema() throws ClassNotFoundException {
List<Schema.Field> fields = new ArrayList<>();
fields.add(new Schema.Field("key", Schema.create(Schema.Type.STRING), "Doc: key field", (Object) null));
Schema.Field f = new Schema.Field("type", ReflectData.get().getSchema(ClassUtils.getClass(((Class) this.type).getName())), "Doc: type field", (Object) null);
f.addProp("java-class", ((Class) this.type).getName());
fields.add(f);
fields.add(new Schema.Field("value", ReflectData.get().getSchema(value.getClass()), "Doc: value field", (Object) null));
return Schema.createRecord(((Class) this.type).getName() + "Param", "Doc: param record", this.getClass().getPackage().getName(), false, fields);
}
But in this case, avro will throw ClassCastException, because it can't cast Class to Boolean, Integer etc. I always had a lot of problems working with avro and java Types and Classes.
So the best advice i think will be to change you model (Parcel, PluginDump and Param i mean) to have less problems with avro. For example you can store type name like a string, and get a Type with reflection after deserializing.

how to access dynamically created radiobuttons in mvc3

foreach (var qList in Model) {
#Html.RadioButton("InputAnswer[" + index + "]", "Yes", false,
new { onclick = "LoadQuestion('" + qList.ID + "','Yes')" })<label>Yes</label>
#Html.RadioButton("InputAnswer[" + index + "]", "No", false,
new { onclick = "LoadQuestion('" + qList.ID + "','No')" })<label>No</label>
}
Based on the model it will create 1 , 2 , 3 or 4 set's of radio buttons as ( Yes & No). I need to get the input from the radio button's ( Yes or No ) and i need to display child controls dynamically.
Need Help: Please provide me some help. It would be great if you could suggest me how to take up this task from controller -> model -> view.
The easiest way is to just pass
LoadQuestion(this)
in the LoadQuestion javascript call. That will give you a reference to the current radiobutton that was clicked. Then you can use that reference to interrogate the radiobutton for information (id, value, checked, etc...) That should then allow you to toggle other values based on the state of the radiobutton.

How to Detect Diferences between GET and POST ViewModel Values in a form?

I have a single view that handles a lot of Models of type VoyagesViewModel, in that view the user can create a new voyage or edit all the active voyages, so i have different instances of the same object type in that view.
each form contains something like:
<% = Html.Hidden("Voyages["+ i +"].VoyageDetails[" + i2 + "].Id", location.Id)%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", location.ArrivalDate, new { #class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].ArrivalDate", "*")%>
<% = Html.TextBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", location.DepartureDate, new { #class = "dates" })%><% = Html.ValidationMessage("Voyages[" + i + "].VoyageDetails[" + i2 + "].DepartureDate", "*")%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationID", location.LocationID)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].LocationName", location.LocationName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselName", location.VesselName)%>
<% = Html.Hidden("Voyages[" + i + "].VoyageDetails[" + i2 + "].VesselID", location.VesselID)%>
<% = Html.CheckBox("Voyages[" + i + "].VoyageDetails[" + i2 + "].remove", location.remove)%> (remove)
I have 8 to 10 of this in that View, when the user POST the form(I have all this fields in a single form), i want to be able to detect if the user change something in a voyage to save it, so i don't have to save that specific voyage if no changes where made.
To check this i have a hidden field and i do this:
<% = Html.Hidden("Voyages[" + i + "].hash", TamperProofing.GetExpiringHMAC(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model), DateTime.Now.AddMinutes(15)))%>
Im using HMAC to get a hashed version of the hole object, but first i serialize the object into a string format (JSON Format):
{"Id":22,"VesselName":"CAPTAIN P (CPP)","VesselID":8,"VoyageDetails":[{"Id":58,"ArrivalDate":"\/Date(1259298000000)\/","DepartureDate":"\/Date(1259384400000)\/","LocationID":404,"LocationHash":null,"LocationName":"Balboa, Panama (PABLB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":60,"ArrivalDate":"\/Date(1260248400000)\/","DepartureDate":"\/Date(1260334800000)\/","LocationID":406,"LocationHash":null,"LocationName":"Colon Free Zone, Panama (PACFZ)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":61,"ArrivalDate":"\/Date(1260421200000)\/","DepartureDate":"\/Date(1260507600000)\/","LocationID":407,"LocationHash":null,"LocationName":"Cristobal, Panama (PACTB)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":62,"ArrivalDate":null,"DepartureDate":null,"LocationID":408,"LocationHash":null,"LocationName":"Manzanillo, Panama (PAMAN)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":false},{"Id":59,"ArrivalDate":null,"DepartureDate":null,"LocationID":405,"LocationHash":null,"LocationName":"Coco Solo, Panama (PACSO)","VesselName":"CAPTAIN P (CPP)","VesselID":8,"Order":0,"Comment":null,"remove":true}],"newVoyageDetail":null,"isComplete":false,"Code":"A Code","position":0,"hash":null}
So when the user POST the form i check if changes where made to each voyage like this:
var obj = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(_voyage);
if (TamperProofing.VerifyChanges(obj, hash) == TamperProofing.HMACChanged.True)
{
//UPDATE
}else
{
//DO Nothing, is the exact same object
}
Serialize it again and compare both hashes, the one on the hidden against the recently calculated one, if it match it means nothing changed.
All works pretty well, i was just wondering, if there are any other options to do this?
And my other concern is the time that can take the serialization and all the HMAC thing with this large string generated by the Serialization against the time it could take just to Update unchanged object again to the DB.
EDIT: I don't need to know which field changed, just if something changed.
If server performance is a concern, you might consider creating a "changed" field for each record and using Javascript to set it when one of the user-editable field values changes.
To ensure correctness in downlevel browsers or NoScript fringe cases, a common pattern is to use a tri-state value, with one state meaning "unknown" or "JS disabled". For example, you initialize the fields on the server to 0 (or empty), have your JS code set them all to 1 on load, and then to 2 when the field is modified. If your server sees a 0/null/empty on POST, then it falls back on the server-side method, in this case your hash-compare. If it's set to 1, then it ignores that record, and if it's set to 2, then it automatically triggers an update.
This way, you could avoid computing hashes in 99% of cases, and still correctly handle the outliers.
This doesn't necessarily prevent tampering but you weren't too specific about what kind of tampering you're trying to prevent. The most effective means of tamper-proofing is really to keep the object or information out of reach in the first place, i.e. in the session state or an encrypted cookie.
Does that help at all?

Resources