-
Notifications
You must be signed in to change notification settings - Fork 9
Home
The T.A.R.A.L.L.O. inventory system comes with a fancy API that lets you obtain and update information about the items, add and delete items via HTTP requests.
The API uses JSON format for gathering requests contents and for giving responses.
- Managing the session and Authentication
- Getting an Item
- Adding a new Item
- Updating an Item
- Deleting and restoring an Item
- Validation and "fixup"
- Moving and Losing an Item
- Searching an Item
- Getting history and logs
- Getting summary of an Item
- Getting stats
- Adding bulk items
- Creating a product
- Renaming a product
- Getting a product
- Updating a product
- Deleting a product
- Autosuggest Items
For authenticating yourself, you need to put in the HTTP header of the request the Key Authorization
and in the value the string Token
, a space and the token obtained from TARALLO.
e.g. Authorization: Token yoLeCHmEhNNseN0BlG0s3A:ksfPYziGg7ebj0goT0Zc7pbmQEIYvZpRTIkwuscAM_k
Specifically, that's the default token for the development version. When you do a make up
, you get that token already configured.
If you want to add more tokens (e.g. in production):
- Open TARALLO
- Go to Options
- Type any description ("My awesome program that accesses the APIs")
- Press "Get token"
- Copy the token from the green confirmation message
Part of the token is hashed in the database, that's why it's replaced by ********** in the table, copy it from the green thing 'cause that's the only time you're going to see it un-hashed and in plain text.
Do a GET request to /v2/session
.
In case of session expired or user not authenticated the response will look like this:
{
"exception": "WEEEOpen\\Tarallo\\HTTP\\AuthenticationException",
"message": "Not authenticated or session expired"
}
If the session is valid the response will look like this:
{
"username": "John.Doe",
"cn": "John Doe",
"level": 0
}
Response codes:
200
- The user is authenticated (valid session)
401
- The user is not authenticated or session has expired
Do a GET request to /v2/items/CODE
, where CODE is the Item code.
You must use the session cookie to authenticate this request.
If the Item exists in the database, the response will look like this:
{
"code": "95",
"features": {
"brand": "HP",
"model": "Compaq nc6000 (PD468AA#ABZ)",
"motherboard-form-factor": "proprietary-laptop",
"notes": "Supporta PXE (attivare in BIOS > security, F12 per usarlo), A61 adatto. No PAE, usare \"forcepae\" e parte. Scheda wifi rilevata ma è disattivata e non trova reti, capire perché. La batteria dura 38 min. Lettore di schede SD.",
"os-license-code": "TH1S-1SN0T-AV4L-1DPR-0DUC-TK3Y",
"os-license-version": "Windows XP Professional",
"power-connector": "barrel",
"psu-ampere": 3.5,
"psu-volt": 18.5,
"sn": "CNU666D24G",
"software": "Xubuntu 18.04 LTS",
"type": "case",
"working": "yes"
},
"contents": [
{
"code": "B117",
"features": {
"brand": "HP",
"ethernet-ports-1000m-n": 1,
"ide-ports-n": 1,
"integrated-graphics-brand": "ATI",
"integrated-graphics-model": "Mobility Radeon 9600/9700",
"key-bios-setup": "F10",
"mac": "c0:ff:ee:b3:33:3f",
"mini-jack-ports-n": 2,
"mini-pci-sockets-n": 1,
"model": "0890h",
"motherboard-form-factor": "proprietary-laptop",
"owner": "DISAT",
"parallel-ports-n": 1,
"ram-form-factor": "sodimm",
"ram-type": "ddr",
"rj11-ports-n": 1,
"s-video-ports-n": 1,
"serial-ports-n": 1,
"type": "motherboard",
"vga-ports-n": 1,
"working": "yes"
},
"contents": [
{
"code": "C122",
"features": {
"brand": "Intel",
"core-n": 1,
"frequency-hertz": 1700000000,
"model": "Pentium M 1.70 GHz",
"owner": "DISAT",
"type": "cpu",
"variant": "17",
"working": "yes"
}
},
{
"code": "R101",
"features": {
"brand": "Nanya",
"capacity-byte": 536870912,
"frequency-hertz": 167000000,
"model": "NT512D64SH8A0FM-6K",
"owner": "DISAT",
"ram-form-factor": "sodimm",
"ram-type": "ddr",
"type": "ram",
"working": "yes"
}
},
{
"code": "W5",
"features": {
"brand": "HP",
"brand-manufacturer": "Intel",
"mac": "00:0e:35:7d:33:b0",
"mini-pci-sockets-n": 1,
"model": "PRO/Wireless 2200BG",
"sn": "CNX7373ASD",
"type": "wifi-card"
}
}
]
},
{
"code": "HDD197",
"features": {
"brand": "Hitachi",
"capacity-decibyte": 40000000000,
"hdd-odd-form-factor": "2.5-9.5mm",
"mini-ide-ports-n": 1,
"model": "MK4026GAX",
"owner": "DISAT",
"smart-data": "ok",
"sn": "X1HF4444T",
"spin-rate-rpm": 5400,
"type": "hdd",
"working": "yes"
}
},
{
"code": "ODD138",
"features": {
"brand": "HL-DT-ST",
"color": "black",
"hdd-odd-form-factor": "laptop-odd-9.5mm",
"jae-ports-n": 1,
"model": "RW/DVD GCC-4243N",
"notes": "Scrive i CD ma i DVD li legge solo solo... 💿",
"odd-type": "dvd-r",
"owner": "DISAT",
"type": "odd"
}
}
],
"location": [
"Polito",
"LabFis4",
"ArmadioL"
]
}
However, note that products and items are merged. This is easier when you just want to read, but if you plan to modify an item in some way it's not ideal.
Alternatively, you can make a request to /v2/items/CODE?separate
.
Compare, without ?separate
(item and product merged):
{
"code": "R777",
"features": {
"capacity-byte": 536870912,
"color": "green",
"frequency-hertz": 667000000,
"ram-ecc": "no",
"ram-form-factor": "dimm",
"ram-type": "ddr2",
"type": "ram",
"brand": "Samsung",
"model": "S667ABC512",
"sn": "ASD10A7C123456",
"variant": "v1",
"working": "no"
},
"location": [
"Polito",
"Chernobyl",
"Table",
"RamBox"
]
}
and with ?separate
:
{
"code": "R777",
"features": {
"brand": "Samsung",
"model": "S667ABC512",
"sn": "ASD10A7C123456",
"variant": "v1",
"working": "no"
},
"product": {
"brand": "Samsung",
"model": "S667ABC512",
"variant": "v1",
"features": {
"capacity-byte": 536870912,
"color": "green",
"frequency-hertz": 667000000,
"ram-ecc": "no",
"ram-form-factor": "dimm",
"ram-type": "ddr2",
"type": "ram"
}
},
"location": [
"Polito",
"Chernobyl",
"Table",
"RamBox"
]
}
Response codes:
200
- Item found
404
- Item not found
401
- The user is not authenticated or session has expired
There's a GET /v1/features/{feature}/{value}
endpoint that returns a list of items with a given feature value that must match exactly. Only text features are supported, i.e. the ones that you type into a text box (no dropdown, no numeric values with units, etc...).
It returns only the codes of the first few items, so it is useful only for features that should be unique, like serial numbers. The code that feeds the endpoint is used internally to find duplicate serial numbers, for example.
Examples:
GET /v2/features/sn/CN0M618F179729260FVOA00
{
"status": "success",
"data": [
"A5"
]
}
GET /v2/features/sn/serial-number-that-doesnt-exist
{
"status": "success",
"data": []
}
Response codes:
200
- Request succeeded (may contain results or an empty array)
401
- The user is not authenticated or session has expired
If you need anything more complex or expect a lot of results, use the search
endpoints.
Requests:
POST /v2/items
If you want to manually assign a code use a PUT request instead
PUT /v2/items/{CODE}
If some items don't have a code, the server will try to generate one for each item.
You must use the session cookie to authenticate this request.
The request body should look like this:
{
"parent": "SomeLocation",
"features": {
"brand": "Dill",
"model": "XP-S92",
"type": "case"
},
"contents": []
}
It's also possible to add a tree of items. In that case, if you want to
specify a code for inner items, you should use the "code"
parameter.
The "code" parameter is not allowed for outer items.
{
"parent": "SomeLocation",
"features": {
"model": "XP-S92",
"brand": "Dill",
"type": "case"
},
"contents": [
{
"features": {
"type": "motherboard",
"brand": "Dell",
"model": "F00-B4R"
},
"contents": [
{
"features": {
"type": "cpu",
"brand": "Intel",
"model": "Core 3 Trio E3800",
"frequency-hertz": "2800000000"
},
"contents": []
}
]
},
{
"code": "ASD",
"features": {
"type": "psu",
"brand": "Gamma Electronics",
"model": "ASD-400W"
},
"contents": []
}
]
}
Responses contain the item code as the only data:
{"status": "success", "data": "PC42"}
or you may use the ?loopback
parameter to request a
copy of the entire item, e.g. do a POST /v2/items?loopback
or a PUT /v2/items/CODE?loopback
.
In any case, the response contains a Location:
header with
the URL of the newly added item, e.g.:
Location: /v2/items/PC42
Response codes:
201
- Item created
400
- Bad request (malformed JSON, validation failed, location does not exist, etc...)
401
- The user is not authenticated or session has expired
403
- The user doesn't have permission to add new items
404
- Item code contains invalid characters. Yes this is a bug and will be fixed someday
Request:
PATCH /v2/items/{id}/features
The body of the request must contain a JSON where you put every feature you want to change, with the new value. Other features will be unchanged.
Example:
{
"feature1": "value1",
"feature2": "value2",
"feature3": "value3"
}
Request:
PUT /v2/items/{id}/features
Set the features of an item and delete every other features. The body is the same as above
Request:
DELETE /v2/items/CODE
Not that items that contain other items cannot be deleted and there's not API endpoint for recursive deletion, you'll have to delete their content or move it elsewhere. If you try to delete them, you'll get this 400 response:
{
"status": "fail",
"data": {
"*": "Cannot delete an item while contains other items"
}
}
Response codes:
204
- Item deleted successfully
400
- Invalid code item code (this will become a 404 some day)
400
- Items contains other items
401
- User not authenticated or session expired
403
- User not authorized to delete items
404
- Item doesn't exist or already deleted
Items can be only soft-deleted: that is, they are removed from the item tree and any attempt to get them will return a 404, but they still retain all their features and can be recovered.
You can check if an item has been soft deleted and thus can be recovered with
GET /v2/deleted/R420
This means it has been deleted but can be recovered:
{
"status": "success",
"data": "2018-11-16T23:28:01+00:00"
}
The data is the deletion time and date.
A 404 response on the other hand means that it still exists and hasn't been deleted, or it never existed, or it has been permanently deleted and cannot be recovered.
Response codes:
200
- Item has been soft-deleted and can be recovered
401
- User not authenticated or session expired
404
- Item is not in the trash can (not deleted or not existing)
It has been deleted but you still need it? Good, there's a way to recover it!
Do a
PUT /v2/deleted/CODE/parent
the request body must be a JSON string (delimited by "") that is the item code of the parent item where the recovered item will be placed.
That is, to place R420 into computer 94, the request will look like this:
PUT /v2/deleted/R420/parent HTTP/1.1
Host: 127.0.0.1:8080
content-type: application/json
Cookie: ...
"94"
If the operation succeeds, you'll get a 201 response with no body.
If it doesn't, you may get this kind of responses:
{
"status": "fail",
"data": {
"*": "Parent item doesn't exist"
}
}
{
"status": "fail",
"data": {
"*": "Request body should be a string"
}
}
Response codes:
201
- Item has been restored
400
- Malformed request or parent item doesn't exist
401
- User not authenticated or session expired
403
- User not authorized to move items around
404
- Item is not in the trash can (not deleted or not existing)
All items go through a two-step validation process, that takes into account their features and their location:
- Fixup: try to move misplaced items to their correct location
- Validation: check that no impossible placements are still there, accept or reject the entire request accordingly
For instance, fixup moves RAM modules from a case to the motherboard contained inside it. If the motherboard could not be found or the fixup could not be applied, the request still goes through to the next phase.
Validation checks that RAM and motherboards have the same socket, and does the same for CPUs and motherboards, and prevents impossible placements like a CPU inside a HDD, and the like. If any validation step fails, the entire request is rejected.
This is done both for newly added items, and for "move" operations,
even moves that restore deleted items.
The src/ItemLocationValidator.php
file contains the code that does
all these checks.
Both validation and fixup can be disabled on a per-request basis, with
a parameter which will not be named since you shouldn't use it: if you
really (and desperately) need it, check APIv2/Controller.php
.
Request:
PUT /v2/items/{id}/parent
The body of the request must be a string that is the name of the new location
Body example:
ArmadioL
Request:
DELETE /v2/items/{id}/parent
In case you lost an item and don't know where is it.
Request:
POST /v2/search
In the body you put all the parameters you need to search
Example:
{
"location": "Rambox",
"features": {
"type": "case",
"brand": "HP"
}
}
You will get an id in response
Request:
PATCH /v2/search/{id}
Filter your previous search, where id is the id of the search
Example:
{
"features": {
"working": "yes"
}
}
You will get an id in response
Request:
GET /search/{id}[/page/{page}]
Request:
GET /v2/items/{id}/history
Return:
- change
string
the change occured, see the list below - other
string
where is moved, if moved, else null - time
string
when the change happened - user
string
who made the change
Change char list:
- C: create
- U: update, feature(s) are modificated
- M: move
- D: delete
- R: rename
- L: lose
Example:
[
{
"change": "M",
"other": "B25",
"time": "1590355283.959208",
"user": "ExampleScript"
},
{
"change": "U",
"other": null,
"time": "1590355283.956257",
"user": "ExampleScript"
},
{
"change": "C",
"other": null,
"time": "1590355283.949887",
"user": "ExampleScript"
}
]
TODO
Request:
GET /getItemsForEachValue/{feature}[/{filter}[/{location}[/{creation}[/{deleted}]]]]
Send this request to get a list of item IDs that have a certain feature. They will be grouped by feature value. If filter is specified it will show only IDs of items that have that particular feature of that particular value. If none exist it will return an empty array. Example response below.
-
feature
Feature name to look for -
filter
The value you want the feature to be -
location
Only items that are in a location -
limit
Maximum number of results -
creation
creation date (starts from here) -
deleted
Also count deleted/lost items
GET /getItemsForEachValue/color
{
"green": ["B100", "B200", "..." ],
"red": ["C100", "C200", "..." ]
}
GET /getItemsForEachValue/color/green
{
"green": ["B100", "B200", "..." ]
}
GET /getItemsForEachValue/color/teal
[]
Request:
GET /getItemByNotFeature/{filter}/{notFeature}[/{location}[/{limit}[/{creation}[/{deleted}]]]]
Send this request to get a list of items with the feature in filter
and don't have a feature
specified in notFeature
-
filter
feature that should be there write astype
=value
-
notFeature
Feature that should not be present at all -
location
Only items that are in a location -
limit
Maximum number of results -
creation
creation date (starts from here) -
deleted
Also count deleted/lost items
Example:
/getItemByNotFeature/type=cpu/brand
will return the list of CPUs without a brand specified
Request:
GET /getRecentAuditByType/{type}[/{howMany}]
Get all recent changes filtered by change type
-
type
the change you want to filter. See the list below. -
howMany
how many changes you want to receive. Default is 100.
Change char list:
- C: create
- U: update, feature(s) are modified
- M: move
- D: delete
- R: rename
- L: lose
You will get a json with format "code": "time of the change" Example:
{
"203": "1602753536.986703",
"R87": "1602753562.273268",
"B237": "1602753524.907019",
"C254": "1602751601.707732",
"D12": "1602491494.600757"
}
Request:
GET /getCountByFeature/{feature}[/{filter}[/{location}[/{creation[/{deleted[/{cutoff}]]]]]
Return the count of items with a specific set of feature
-
feature
The feature you want to count -
filter
Feature that must match, useful to select items by type -
location
Consider only in this location and subtree -
creation
Creation date -
deleted
Also count deleted/lost items, defaults to false (don't count them) -
cutoff
Report features only if count is greater than (or equal to) this number, useful for text features with lots of possible values
Request:
POST /v2/bulk/add/{identifier}
Call this request to bulk add items. You must chose an identifier for the bulk. You can add ?overwrite=yes at the end if you want to replace a bulk with the same identifer.
The body must be a json array specifying for each element if is a item or a product with the parameter "type"="I"/"P"
Example:
[
{
"type": "I",
"features": {
"brand": "Olidata",
"model": "Denver 69000",
"variant": "default",
"type": "case",
"working": "yes"
},
"contents": [
{
"features": {
"brand": "ASUSTek Computer inc.",
"model": "P5KPL-VM",
"variant": "default",
"mac": "00:1a:22:52:a4:be",
"sn": "MT707BK05303585",
"type": "motherboard",
"working": "yes"
},
"contents": [
{
"code": "C251",
"features": {
"brand": "Intel",
"model": "Core 2 Duo E8200",
"variant": "default",
"type": "cpu",
"working": "yes"
}
},
{
"features": {
"brand": "Samsung",
"model": "M3 78T2863DZS-CF7",
"sn": "589442786",
"variant": "default",
"type": "ram",
"working": "yes"
}
},
{
"code": "R597",
"features": {
"brand": "Samsung",
"model": "M3 78T2953EZ3-CF7",
"sn": "1231847313",
"variant": "default",
"type": "ram",
"working": "yes"
}
}
]
}
]
},
{
"type": "P",
"brand": "Samsung",
"model": "M3 78T2953EZ3-CF7",
"variant": "default",
"features": {
"capacity-byte": 1073741824,
"color": "green",
"frequency-hertz": 800000000,
"ram-ecc": "no",
"ram-form-factor": "dimm",
"ram-timings": "6-6-6-18 as DDR2-800",
"ram-type": "ddr2",
"type": "ram"
}
},
{
"type": "P",
"brand": "Intel",
"model": "Core 2 Duo E8200",
"variant": "default",
"features": {
"core-n": 2,
"cpu-socket": "lga775",
"frequency-hertz": 2660000000,
"isa": "x86-64",
"thread-n": 2,
"type": "cpu"
}
},
{
"type": "P",
"brand": "ASUSTek Computer inc.",
"model": "P5KPL-VM",
"variant": "default",
"features": {
"color": "golden",
"cpu-socket": "lga775",
"ethernet-ports-1000m-n": 1,
"integrated-graphics-brand": "Intel",
"integrated-graphics-model": "82G33/G31 Express",
"key-bios-setup": "Del",
"mini-jack-ports-n": 3,
"motherboard-form-factor": "microatx",
"ps2-ports-n": 2,
"psu-connector-cpu": "4pin",
"psu-connector-motherboard": "atx-24pin",
"ram-form-factor": "dimm",
"ram-type": "ddr2",
"sata-ports-n": 4,
"serial-ports-n": 1,
"type": "motherboard",
"usb-ports-n": 4,
"vga-ports-n": 1
}
}
]
Request:
PUT /v2/products/{brand}/{model}/{variant}
Where brand
, model
and variant
are the parameter of the new product.
In the body you must put a json array with the features of the product.
Add ?loopback=yes
a the end if you want the product created as a JSON response.
Request:
GET /v2/products/{brand}/{model}/{variant}
Where brand
, model
and variant
are the paramenters of the product you want to get.
Return a JSON of the product.
Request:
GET /v2/products/{brand}/{model}
You can also get more than one product by not specifying the variant
Request:
PATCH /v2/products/{brand}/{model}/{variant}
The brand
, model
and variant
in the request are of the product you want to rename.
In the body you put a JSON array with the new brand, model and variant.
Add ?loopback=yes
at the end of the request if you want the renamed product in response.
Request:
PATCH /v2/products/{brand}/{model}/{variant}/features
The brand
, model
and variant
in the request are of the product you want to rename.
In the body you put a JSON array with the new brand, model and variant: specify features to update and to delete, other are left as they are.
Add ?loopback=yes
at the end of the request if you want the renamed product in response.
Request:
POST /v2/products/{brand}/{model}/{variant}/features
The brand
, model
and variant
in the request are of the product you want to rename.
In the body you put a JSON array with the new brand, model and variant: delete every feature, replace with new ones.
Add ?loopback=yes
at the end of the request if you want the renamed product in response.
Request:
DELETE /v2/products/{brand}/{model}/{variant}
Delete the product with the same parameters in the request
This request is used in autosuggest to fetch items with the typed initials.
Requests:
GET /v2/autosuggest/code?q={chars}
where chars is the initials of the item
Example:
/v2/autosuggest/code?q=hdd1
return up to 10 items with initial code hdd1 (ex. hdd101, hdd105 etc...)
This request is used in autosuggest to fetch locations with the typed initials.
Requests:
GET /v2/autosuggest/location?q={chars}
where chars is the initials of the item, returns an array of object with name
and color
(might be null) of the locations. max 10 locations
Example:
GET /v2/autosuggest/location?q=box
[
{
"name" : "CpuBox",
"color" : null
},
{
"name" : "RamBox",
"color" : "red"
}
]