Page Menu
Home
Sealhub
Search
Configure Global Search
Log In
Files
F969522
Phabricator.node.ts
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
Phabricator.node.ts
View Options
import
{
IExecuteFunctions
,
INodeExecutionData
,
INodeType
,
INodeTypeDescription
,
NodeExecutionWithMetadata
,
NodeParameterValueType
,
}
from
'n8n-workflow'
;
import
qs
from
'qs'
;
import
{
constraints
}
from
'./constraints'
;
import
{
fields
,
PREFIXES
}
from
'./fields'
;
import
{
methods
,
apps
}
from
'./methods'
;
import
{
short_descriptions
}
from
'./short-descriptions'
;
const
APP_FILTER
=
[
'maniphest'
,
'transaction'
,
'project'
];
function
evaluate
(
context
:
IExecuteFunctions
,
value
:
NodeParameterValueType
,
index
:
number
,
)
:
NodeParameterValueType
{
if
(
typeof
value
==
'string'
&&
value
.
startsWith
(
'='
))
{
value
=
context
.
evaluateExpression
(
value
,
index
);
if
(
typeof
value
==
'string'
&&
value
.
startsWith
(
'='
))
{
value
=
value
.
slice
(
1
);
}
}
return
value
;
}
async
function
runForItem
(
this
:
IExecuteFunctions
,
index
:
number
)
:
Promise
<
any
>
{
const
{
token
,
domain
}
=
(
await
this
.
getCredentials
(
'phabricatorApi'
))
as
{
token
:
string
;
domain
:
string
;
};
const
parameters
=
{
...
this
.
getNode
().
parameters
};
const
{
operation
}
=
parameters
;
for
(
const
key
in
parameters
)
{
this
.
sendMessageToUI
(
key
);
let
value
=
parameters
[
key
];
this
.
sendMessageToUI
(
value
);
let
actual_key
=
key
;
value
=
evaluate
(
this
,
value
,
index
);
if
(
parameters
[
key
]
==
''
)
{
delete
parameters
[
key
];
continue
;
}
if
(
key
.
startsWith
(
PREFIXES
.
json
))
{
this
.
sendMessageToUI
(
'Starts with json prefix'
);
this
.
sendMessageToUI
((
value
as
any
).
toString
());
try
{
value
=
JSON
.
parse
(
value
as
string
);
}
catch
(
e
)
{
if
((
value
as
any
)[
PREFIXES
.
transaction_array
]
!==
undefined
)
{
value
=
(
value
as
any
)[
PREFIXES
.
transaction_array
];
(
value
as
any
).
value
=
evaluate
(
this
,
value
,
index
);
}
else
{
throw
e
;
}
}
actual_key
=
actual_key
.
replace
(
PREFIXES
.
json
,
''
);
delete
parameters
[
key
];
}
if
(
actual_key
==
'attachments'
)
{
value
=
Object
.
fromEntries
((
value
as
string
[]).
map
((
key
)
=>
[
key
,
true
]));
}
if
(
actual_key
.
startsWith
(
PREFIXES
.
constraint
))
{
actual_key
=
actual_key
.
replace
(
PREFIXES
.
constraint
,
''
);
if
(
!
parameters
.
constraints
)
{
parameters
.
constraints
=
{};
}
(
parameters
.
constraints
as
any
)[
actual_key
]
=
value
;
this
.
sendMessageToUI
(
actual_key
);
this
.
sendMessageToUI
(
constraints
[
operation
as
string
][
actual_key
]
?
.
type
.
startsWith
(
'list<'
));
this
.
sendMessageToUI
(
!
Array
.
isArray
(
value
));
if
(
/^(Optional )?list</
.
test
(
constraints
[
operation
as
string
][
actual_key
]
?
.
type
))
{
if
(
!
Array
.
isArray
(
value
))
{
this
.
sendMessageToUI
(
'Changing to array!'
);
(
parameters
.
constraints
as
any
)[
actual_key
]
=
value
?
.
toString
().
split
(
','
)
||
[];
}
}
delete
parameters
[
key
];
}
else
{
parameters
[
actual_key
]
=
value
;
}
}
for
(
const
key
of
[
'token'
,
'resource'
,
'operation'
])
{
delete
parameters
[
key
];
}
const
request
=
{
url
:
domain
+
'/api/'
+
this
.
getNodeParameter
(
'operation'
,
index
),
headers
:
{
'Content-Type'
:
'application/x-www-form-urlencoded'
,
},
body
:
qs
.
stringify
({
'api.token'
:
token
,
...
parameters
}),
method
:
<
const
>
'POST'
,
};
this
.
sendMessageToUI
(
request
);
return
this
.
helpers
.
httpRequest
(
request
);
}
export
class
Phabricator
implements
INodeType
{
description
:
INodeTypeDescription
=
{
displayName
:
'Phabricator'
,
name
:
'phabricator'
,
icon
:
'file:phabricator.svg'
,
group
:
[
'transform'
],
version
:
1
,
subtitle
:
'={{$parameter["operation"]}}'
,
description
:
'Interact with Phabricator'
,
defaults
:
{
name
:
'Phabricator'
,
},
inputs
:
[
'main'
],
outputs
:
[
'main'
],
credentials
:
[
{
name
:
'phabricatorApi'
,
required
:
true
,
},
],
properties
:
[
{
displayName
:
'Resource'
,
name
:
'resource'
,
type
:
'options'
,
noDataExpression
:
true
,
options
:
apps
.
map
((
method
)
=>
({
name
:
method
,
value
:
method
,
action
:
method
,
description
:
`Call
${
method
}
Conduit method`
,
})),
default
:
'user.whoami'
,
},
...
apps
.
filter
((
app
)
=>
APP_FILTER
.
includes
(
app
))
.
map
((
app
)
=>
({
displayName
:
'Operation'
,
name
:
'operation'
,
type
:
<
const
>
'options'
,
noDataExpression
:
true
,
description
:
'Choose an operation'
,
required
:
true
,
displayOptions
:
{
show
:
{
resource
:
[
app
],
},
},
options
:
Object
.
entries
(
methods
)
.
filter
(([
method_name
])
=>
{
return
method_name
.
startsWith
(
app
+
'.'
);
})
.
map
(([
method_name
,
method
])
=>
({
name
:
method_name
,
value
:
method_name
,
description
:
method
.
description
,
action
:
method_name
.
split
(
'.'
).
slice
(
1
).
join
(
'.'
)
+
': '
+
short_descriptions
[
method_name
],
})),
default
:
Object
.
keys
(
methods
).
filter
((
method_name
)
=>
method_name
.
startsWith
(
app
+
'.'
),
)[
0
],
})),
...
fields
,
],
};
async
execute
(
this
:
IExecuteFunctions
,
)
:
Promise
<
INodeExecutionData
[][]
|
NodeExecutionWithMetadata
[][]
|
null
>
{
const
items
=
this
.
getInputData
();
const
promises
=
[];
for
(
let
i
=
0
;
i
<
items
.
length
;
i
++
)
{
promises
.
push
(
runForItem
.
bind
(
this
)(
i
));
}
const
responses
=
await
Promise
.
all
(
promises
);
return
[
this
.
helpers
.
returnJsonArray
(
responses
)];
}
}
File Metadata
Details
Attached
Mime Type
text/x-java
Expires
Sat, Nov 23, 04:50 (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
547851
Default Alt Text
Phabricator.node.ts (5 KB)
Attached To
Mode
rNPN n8n-phabricator-node
Attached
Detach File
Event Timeline
Log In to Comment