Skip to content

Commit b70c3f5

Browse files
author
James Brundage
committed
feat: Set-Neocities ( Fixes #3 )
1 parent d0a3ee8 commit b70c3f5

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

Commands/Set-Neocities.ps1

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
function Set-Neocities
2+
{
3+
<#
4+
.SYNOPSIS
5+
Sets Neocities files
6+
.DESCRIPTION
7+
Sets files on Neocities website using the neocities API.
8+
#>
9+
[CmdletBinding(DefaultParameterSetName='upload')]
10+
param(
11+
# The path to the file to upload, or a dictionary of files and their contents.
12+
[Parameter(ValueFromPipelineByPropertyName)]
13+
[Alias('Fullname','FilePath','Path')]
14+
[PSObject]
15+
$File,
16+
17+
# The neocities credential
18+
[Parameter(ValueFromPipelineByPropertyName)]
19+
[Alias(
20+
'Credentials', # Plural aliases are nice
21+
'PSCredential', # so are parameters that match the type name.
22+
'NeocitiesCredential', # A contextual alias is a good idea, too.
23+
'NeocitiesCredentials' # And you may need to pluralize that contextual alias.
24+
)]
25+
[PSCredential]
26+
$Credential,
27+
28+
# The access token
29+
[Parameter(ValueFromPipelineByPropertyName)]
30+
[string]
31+
$AccessToken
32+
)
33+
34+
begin {
35+
$NeocitiesApi = "https://neocities.org/api"
36+
$multiparts = [Ordered]@{}
37+
$boundary = "boundary"
38+
$contentType = "multipart/form-data; boundary=`"$boundary`""
39+
40+
}
41+
process {
42+
$parameterSet = $PSCmdlet.ParameterSetName
43+
$psuedoNamespace = "neocities"
44+
$pseudoType = "$parameterSet"
45+
$InvokeSplat = [Ordered]@{
46+
Uri = "$NeocitiesApi", $PSCmdlet.ParameterSetName -join '/'
47+
}
48+
49+
# If an access token was provided
50+
if ($AccessToken)
51+
{
52+
# use it
53+
$InvokeSplat.Headers = @{Authorization = "Bearer $AccessToken"}
54+
# and cache it for later use
55+
$script:NeocitiesAccessToken = $AccessToken
56+
}
57+
elseif ($Credential)
58+
{
59+
# If a credential was provided, use it
60+
$InvokeSplat.Credential = $Credential
61+
# and cache it for later use
62+
$script:NeoCitiesCredential = $Credential
63+
# (don't forget to set authentication to basic)
64+
$InvokeSplat.Authentication = 'Basic'
65+
}
66+
elseif ($script:NeocitiesAccessToken) {
67+
# If we had a cached access token, use it
68+
$InvokeSplat.Headers = @{Authorization = "Bearer $($script:NeocitiesAccessToken)"}
69+
}
70+
elseif ($script:NeoCitiesCredential) {
71+
# If we had a cached credential, use it
72+
$InvokeSplat.Credential = $script:NeoCitiesCredential
73+
# and don't forget to set authentication to basic.
74+
$InvokeSplat.Authentication = 'Basic'
75+
}
76+
77+
# If neither an access token nor a credential was provided, we can't do anything.
78+
if (-not $InvokeSplat.Credential -and -not $InvokeSplat.Headers)
79+
{
80+
# so error out.
81+
Write-Error "No -Credential provided"
82+
return
83+
}
84+
85+
$InvokeSplat.ContentType = $contentType
86+
87+
# If we were piped in a file
88+
if ($_ -is [IO.FileInfo]) {
89+
$file = $_ # set the parameter directly
90+
}
91+
92+
# For every file passed in, we need to make a unique request.
93+
foreach ($fileInfo in $file) {
94+
# If this is a file, this is easy
95+
if ($fileInfo -is [IO.FileInfo]) {
96+
# just get the string representation of the file's bytes and add them to the multipart collection
97+
$multiparts[$file.Name] = $OutputEncoding.GetString([IO.File]::ReadAllBytes($file))
98+
}
99+
# If the file was a path, we need to get the file's contents
100+
elseif ($fileInfo -is [string] -and (Test-Path $fileInfo)) {
101+
$multiparts[$fileInfo] = Get-Content -Raw $fileInfo
102+
}
103+
# If the file was a dictionary, treat each key as a file name and each value as the file's contents
104+
elseif ($fileInfo -is [Collections.IDictionary]) {
105+
foreach ($keyValuePair in $fileInfo.GetEnumerator()) {
106+
# If the value is a byte array, convert it to a string
107+
if ($keyValuePair.Value -is [byte[]]) {
108+
$multiparts[$keyValuePair.Key] = $OutputEncoding.GetString($keyValuePair.Value)
109+
}
110+
# If the value is a file, read the file's bytes and convert them to a string
111+
elseif ($keyValuePair.Value -is [IO.FileInfo]) {
112+
$multiparts[$keyValuePair.Key] = $OutputEncoding.GetString([IO.File]::ReadAllBytes($keyValuePair.Value))
113+
}
114+
# If the value is a pth to file, read the file's bytes and convert them to a string
115+
elseif ($keyValuePair.Value -is [string] -and (Test-Path $keyValuePair.Value)) {
116+
$multiparts[$keyValuePair.Key] = Get-Content -Raw $keyValuePair.Value
117+
}
118+
# last but not least, stringify the value and add it to the collection
119+
else
120+
{
121+
$multiparts[$keyValuePair.Key] = "$($keyValuePair.Value)"
122+
}
123+
}
124+
}
125+
}
126+
127+
}
128+
129+
end {
130+
# Despite the content type being multipart, we can actually only send one part at a time:
131+
132+
# Any way we slice it, we'll need to POST the data to the API.
133+
$InvokeSplat.Method = 'POST'
134+
135+
136+
# For each part we've found
137+
foreach ($filePart in $multiparts.GetEnumerator()) {
138+
$InvokeSplat.Body = @(
139+
# Create a bounary
140+
"--$boundary"
141+
# Add the file name and content type to the header
142+
"Content-Disposition: form-data; name=`"$($filePart.Key)`"; filename=`"$($filePart.Key)`""
143+
# We're always uploading this a text/plain with neocities, and we need to set the encoding to whatever we passed.
144+
"Content-Type: text/plain; charset=$($OutputEncoding.WebName)"
145+
# The bounary MIME data must be followed by a newline
146+
"`r`n"
147+
# followed by the file contents
148+
$filePart.Value
149+
# followed by an additional boundary
150+
"--$boundary--"
151+
) -join "`r`n" # (all of these pieces are joined by a newline)
152+
153+
# If -WhatIf was passed, don't actually upload the file, just show the splatted parameters.
154+
if ($WhatIfPreference) {
155+
# (Remove the headers and credential from the splatted parameters, so we don't leak any sensitive information)
156+
$InvokeSplat.Remove('Headers')
157+
$InvokeSplat.Remove('Credential')
158+
$InvokeSplat
159+
continue
160+
}
161+
162+
# Invoke-RestMethod with our splatted parameters, and we'll upload the file.
163+
Invoke-RestMethod @InvokeSplat
164+
}
165+
}
166+
}

0 commit comments

Comments
 (0)