mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2024-12-22 16:26:28 +00:00
add support for files
This commit is contained in:
parent
00fd514da5
commit
e4ce767444
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ node_modules
|
|||||||
/.svelte
|
/.svelte
|
||||||
/build
|
/build
|
||||||
/functions
|
/functions
|
||||||
|
.env
|
||||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -521,9 +521,9 @@ dependencies = [
|
|||||||
"actix-web",
|
"actix-web",
|
||||||
"bs62",
|
"bs62",
|
||||||
"byte-unit",
|
"byte-unit",
|
||||||
|
"dotenv",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"memcache",
|
"memcache",
|
||||||
"mime",
|
|
||||||
"ring",
|
"ring",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -557,6 +557,12 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenv"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
|
@ -20,4 +20,4 @@ ring = "0.16"
|
|||||||
bs62 = "0.1"
|
bs62 = "0.1"
|
||||||
memcache = "0.16"
|
memcache = "0.16"
|
||||||
byte-unit = "4"
|
byte-unit = "4"
|
||||||
mime = "0.3"
|
dotenv = "0.15"
|
||||||
|
@ -97,3 +97,24 @@ fieldset {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
width: 100%;
|
||||||
|
min-height: min(calc(100vh - 30rem), 30rem);
|
||||||
|
margin: 0;
|
||||||
|
border: 2px solid var(--ui-bg-1);
|
||||||
|
resize: vertical;
|
||||||
|
outline: none;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 30rem) {
|
||||||
|
.box {
|
||||||
|
min-height: calc(100vh - 25rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:hover,
|
||||||
|
.box:focus {
|
||||||
|
border-color: var(--ui-clr-primary);
|
||||||
|
}
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
|
export type NoteMeta = { type: 'text' | 'file' }
|
||||||
|
|
||||||
export type Note = {
|
export type Note = {
|
||||||
contents: string
|
contents: string
|
||||||
|
meta: NoteMeta
|
||||||
views?: number
|
views?: number
|
||||||
expiration?: number
|
expiration?: number
|
||||||
}
|
}
|
||||||
export type NoteInfo = {}
|
export type NoteInfo = {}
|
||||||
export type NotePublic = Pick<Note, 'contents'>
|
export type NotePublic = Pick<Note, 'contents' | 'meta'>
|
||||||
|
export type NoteCreate = Omit<Note, 'meta'> & { meta: string }
|
||||||
|
|
||||||
|
export type FileDTO = Pick<File, 'name' | 'size' | 'type'> & {
|
||||||
|
contents: string
|
||||||
|
}
|
||||||
|
|
||||||
type CallOptions = {
|
type CallOptions = {
|
||||||
url: string
|
url: string
|
||||||
@ -32,26 +40,35 @@ async function call(options: CallOptions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function create(note: Note) {
|
export async function create(note: Note) {
|
||||||
|
const { meta, ...rest } = note
|
||||||
|
const body: NoteCreate = {
|
||||||
|
...rest,
|
||||||
|
meta: JSON.stringify(meta),
|
||||||
|
}
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: 'notes',
|
url: 'notes',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
body: note,
|
body,
|
||||||
})
|
})
|
||||||
return data as { id: string }
|
return data as { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(id: string) {
|
export async function get(id: string): Promise<NotePublic> {
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: `notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
})
|
})
|
||||||
return data as NotePublic
|
const { contents, meta } = data
|
||||||
|
return {
|
||||||
|
contents,
|
||||||
|
meta: JSON.parse(meta) as NoteMeta,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function info(id: string) {
|
export async function info(id: string): Promise<NoteInfo> {
|
||||||
const data = await call({
|
const data = await call({
|
||||||
url: `notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
return data as NoteInfo
|
return data
|
||||||
}
|
}
|
||||||
|
13
client/src/lib/files.ts
Normal file
13
client/src/lib/files.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export class Files {
|
||||||
|
static toString(f: File | Blob): Promise<string> {
|
||||||
|
const reader = new window.FileReader()
|
||||||
|
reader.readAsDataURL(f)
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
reader.onloadend = () => resolve(reader.result as string)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromString(s: string): Promise<Blob> {
|
||||||
|
return fetch(s).then((r) => r.blob())
|
||||||
|
}
|
||||||
|
}
|
69
client/src/lib/ui/FileUpload.svelte
Normal file
69
client/src/lib/ui/FileUpload.svelte
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { FileDTO } from '$lib/api'
|
||||||
|
import { Files } from '$lib/files'
|
||||||
|
import { createEventDispatcher } from 'svelte'
|
||||||
|
|
||||||
|
export let label: string = ''
|
||||||
|
let files: File[] = []
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{ file: string }>()
|
||||||
|
|
||||||
|
async function onInput(e: Event) {
|
||||||
|
const input = e.target as HTMLInputElement
|
||||||
|
if (input.files.length) {
|
||||||
|
files = Array.from(input.files)
|
||||||
|
const data: FileDTO[] = await Promise.all(
|
||||||
|
files.map(async (file) => ({
|
||||||
|
name: file.name,
|
||||||
|
type: file.type,
|
||||||
|
size: file.size,
|
||||||
|
contents: await Files.toString(file),
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
console.debug(
|
||||||
|
'files',
|
||||||
|
data.map((d) => d.contents.length)
|
||||||
|
)
|
||||||
|
dispatch('file', JSON.stringify(data))
|
||||||
|
} else {
|
||||||
|
dispatch('file', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<small>
|
||||||
|
{label}
|
||||||
|
</small>
|
||||||
|
<input type="file" on:change={onInput} multiple />
|
||||||
|
<div class="box">
|
||||||
|
{#if files.length}
|
||||||
|
<div>
|
||||||
|
<b>Selected Files</b>
|
||||||
|
{#each files as file}
|
||||||
|
<div class="file">
|
||||||
|
{file.name}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div>
|
||||||
|
<b>No Files Selected</b>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
input {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
69
client/src/lib/ui/ShowNote.svelte
Normal file
69
client/src/lib/ui/ShowNote.svelte
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { FileDTO, NotePublic } from '$lib/api'
|
||||||
|
import { Files } from '$lib/files'
|
||||||
|
import copy from 'copy-to-clipboard'
|
||||||
|
import { saveAs } from 'file-saver'
|
||||||
|
import prettyBytes from 'pretty-bytes'
|
||||||
|
import Button from './Button.svelte'
|
||||||
|
|
||||||
|
export let note: NotePublic
|
||||||
|
|
||||||
|
let files: FileDTO[] = []
|
||||||
|
|
||||||
|
$: if (note.meta.type === 'file') {
|
||||||
|
files = JSON.parse(note.contents) as FileDTO[]
|
||||||
|
}
|
||||||
|
|
||||||
|
$: download = () => {
|
||||||
|
for (const file of files) {
|
||||||
|
downloadFile(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function downloadFile(file: FileDTO) {
|
||||||
|
const f = new File([await Files.fromString(file.contents)], file.name, {
|
||||||
|
type: file.type,
|
||||||
|
})
|
||||||
|
saveAs(f)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p class="error-text">you will <b>not</b> get the chance to see the note again.</p>
|
||||||
|
{#if note.meta.type === 'text'}
|
||||||
|
<div class="note" data-testid="note-result">
|
||||||
|
{note.contents}
|
||||||
|
</div>
|
||||||
|
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button>
|
||||||
|
{:else}
|
||||||
|
{#each files as file}
|
||||||
|
<div class="note file" data-testid="note-result">
|
||||||
|
<b on:click={() => downloadFile(file)}>↓ {file.name}</b>
|
||||||
|
<small> {file.type} - {prettyBytes(file.size)}</small>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<Button on:click={download}>download all</Button>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.note {
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 2px solid var(--ui-bg-1);
|
||||||
|
outline: none;
|
||||||
|
padding: 0.5rem;
|
||||||
|
white-space: pre;
|
||||||
|
overflow: auto;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note b {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note.file {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
@ -4,7 +4,7 @@
|
|||||||
export let color = true
|
export let color = true
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div {...$$restProps}>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<small>{label}</small>
|
<small>{label}</small>
|
||||||
<input type="checkbox" bind:checked={value} />
|
<input type="checkbox" bind:checked={value} />
|
||||||
|
@ -7,28 +7,5 @@
|
|||||||
<small>
|
<small>
|
||||||
{label}
|
{label}
|
||||||
</small>
|
</small>
|
||||||
<textarea {...$$restProps} bind:value />
|
<textarea class="box" {...$$restProps} bind:value />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<style>
|
|
||||||
textarea {
|
|
||||||
width: 100%;
|
|
||||||
min-height: min(calc(100vh - 30rem), 30rem);
|
|
||||||
margin: 0;
|
|
||||||
border: 2px solid var(--ui-bg-1);
|
|
||||||
resize: vertical;
|
|
||||||
outline: none;
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 30rem) {
|
|
||||||
textarea {
|
|
||||||
min-height: calc(100vh - 25rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea:hover,
|
|
||||||
textarea:focus {
|
|
||||||
border-color: var(--ui-clr-primary);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -4,17 +4,20 @@
|
|||||||
import { getKeyFromString, encrypt, Hex, getRandomBytes } from '$lib/crypto'
|
import { getKeyFromString, encrypt, Hex, getRandomBytes } from '$lib/crypto'
|
||||||
|
|
||||||
import Button from '$lib/ui/Button.svelte'
|
import Button from '$lib/ui/Button.svelte'
|
||||||
|
import FileUpload from '$lib/ui/FileUpload.svelte'
|
||||||
import Switch from '$lib/ui/Switch.svelte'
|
import Switch from '$lib/ui/Switch.svelte'
|
||||||
import TextArea from '$lib/ui/TextArea.svelte'
|
import TextArea from '$lib/ui/TextArea.svelte'
|
||||||
import TextInput from '$lib/ui/TextInput.svelte'
|
import TextInput from '$lib/ui/TextInput.svelte'
|
||||||
|
|
||||||
let note: Note = {
|
let note: Note = {
|
||||||
contents: '',
|
contents: '',
|
||||||
|
meta: { type: 'text' },
|
||||||
views: 1,
|
views: 1,
|
||||||
expiration: 60,
|
expiration: 60,
|
||||||
}
|
}
|
||||||
let result: { password: string; id: string } | null = null
|
let result: { password: string; id: string } | null = null
|
||||||
let advanced = false
|
let advanced = false
|
||||||
|
let file = false
|
||||||
let type = false
|
let type = false
|
||||||
let message = ''
|
let message = ''
|
||||||
let loading = false
|
let loading = false
|
||||||
@ -31,6 +34,8 @@
|
|||||||
message = 'the note will expire and be destroyed after ' + fraction
|
message = 'the note will expire and be destroyed after ' + fraction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: note.meta.type = file ? 'file' : 'text'
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
try {
|
try {
|
||||||
error = null
|
error = null
|
||||||
@ -39,6 +44,7 @@
|
|||||||
const key = await getKeyFromString(password)
|
const key = await getKeyFromString(password)
|
||||||
const data: Note = {
|
const data: Note = {
|
||||||
contents: await encrypt(note.contents, key),
|
contents: await encrypt(note.contents, key),
|
||||||
|
meta: note.meta,
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (type) data.expiration = parseInt(note.expiration)
|
if (type) data.expiration = parseInt(note.expiration)
|
||||||
@ -89,15 +95,21 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<form on:submit|preventDefault={submit}>
|
<form on:submit|preventDefault={submit}>
|
||||||
<fieldset disabled={loading}>
|
<fieldset disabled={loading}>
|
||||||
<TextArea
|
{#if file}
|
||||||
label="note"
|
<FileUpload label="file" on:file={(f) => (note.contents = f.detail)} />
|
||||||
bind:value={note.contents}
|
{:else}
|
||||||
placeholder="..."
|
<TextArea
|
||||||
data-testid="input-note"
|
label="note"
|
||||||
/>
|
bind:value={note.contents}
|
||||||
|
placeholder="..."
|
||||||
|
data-testid="input-note"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
|
<Switch class="file" label="file" bind:value={file} />
|
||||||
<Switch label="advanced" bind:value={advanced} />
|
<Switch label="advanced" bind:value={advanced} />
|
||||||
|
<div class="grow" />
|
||||||
<Button type="submit" data-testid="button-create">create</Button>
|
<Button type="submit" data-testid="button-create">create</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -152,11 +164,19 @@
|
|||||||
<style>
|
<style>
|
||||||
.bottom {
|
.bottom {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
/* justify-content: space-between; */
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom :global(.file) {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grow {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.middle-switch {
|
.middle-switch {
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
|
||||||
import copy from 'copy-to-clipboard'
|
|
||||||
|
|
||||||
import type { NotePublic } from '$lib/api'
|
import type { NotePublic } from '$lib/api'
|
||||||
import { info, get } from '$lib/api'
|
import { get, info } from '$lib/api'
|
||||||
import { decrypt, getKeyFromString } from '$lib/crypto'
|
import { decrypt, getKeyFromString } from '$lib/crypto'
|
||||||
import Button from '$lib/ui/Button.svelte'
|
import Button from '$lib/ui/Button.svelte'
|
||||||
|
import ShowNote from '$lib/ui/ShowNote.svelte'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
export let id: string
|
export let id: string
|
||||||
|
|
||||||
@ -29,7 +28,6 @@
|
|||||||
loading = true
|
loading = true
|
||||||
error = null
|
error = null
|
||||||
password = window.location.hash.slice(1)
|
password = window.location.hash.slice(1)
|
||||||
console.log(password)
|
|
||||||
await info(id)
|
await info(id)
|
||||||
exists = true
|
exists = true
|
||||||
} catch {
|
} catch {
|
||||||
@ -61,12 +59,7 @@
|
|||||||
note was not found or was already deleted.
|
note was not found or was already deleted.
|
||||||
</p>
|
</p>
|
||||||
{:else if note && !error}
|
{:else if note && !error}
|
||||||
<p class="error-text">you will not get the chance to see the note again.</p>
|
<ShowNote {note} />
|
||||||
<div class="note" data-testid="note-result">
|
|
||||||
{note.contents}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button>
|
|
||||||
{:else}
|
{:else}
|
||||||
<form on:submit|preventDefault={show}>
|
<form on:submit|preventDefault={show}>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@ -86,16 +79,3 @@
|
|||||||
{#if loading}
|
{#if loading}
|
||||||
<p>loading...</p>
|
<p>loading...</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
|
||||||
.note {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 2px solid var(--ui-bg-1);
|
|
||||||
outline: none;
|
|
||||||
padding: 0.5rem;
|
|
||||||
white-space: pre;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -6,7 +6,8 @@ version: '3.7'
|
|||||||
services:
|
services:
|
||||||
memcached:
|
memcached:
|
||||||
image: memcached:1-alpine
|
image: memcached:1-alpine
|
||||||
entrypoint: memcached -m 128
|
restart: unless-stopped
|
||||||
|
entrypoint: memcached -m 128M -I 4M
|
||||||
ports:
|
ports:
|
||||||
- 11211:11211
|
- 11211:11211
|
||||||
|
|
||||||
|
@ -9,5 +9,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
"npm-run-all": "^4.1.5"
|
"npm-run-all": "^4.1.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
|
"pretty-bytes": "^5.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
pnpm-lock.yaml
generated
15
pnpm-lock.yaml
generated
@ -1,8 +1,14 @@
|
|||||||
lockfileVersion: 5.3
|
lockfileVersion: 5.3
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
|
file-saver: ^2.0.5
|
||||||
http-proxy: ^1.18.1
|
http-proxy: ^1.18.1
|
||||||
npm-run-all: ^4.1.5
|
npm-run-all: ^4.1.5
|
||||||
|
pretty-bytes: ^5.6.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
file-saver: 2.0.5
|
||||||
|
pretty-bytes: 5.6.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
http-proxy: 1.18.1
|
http-proxy: 1.18.1
|
||||||
@ -122,6 +128,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/file-saver/2.0.5:
|
||||||
|
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/follow-redirects/1.14.6:
|
/follow-redirects/1.14.6:
|
||||||
resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==}
|
resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
@ -357,6 +367,11 @@ packages:
|
|||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pretty-bytes/5.6.0:
|
||||||
|
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/read-pkg/3.0.0:
|
/read-pkg/3.0.0:
|
||||||
resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=}
|
resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use actix_web::{middleware, web, App, HttpServer};
|
use actix_web::{middleware, web, App, HttpServer};
|
||||||
|
use dotenv::dotenv;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
@ -10,6 +11,7 @@ mod store;
|
|||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
|
dotenv().ok();
|
||||||
return HttpServer::new(|| {
|
return HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
// .configure(|cfg: &mut web::ServiceConfig| {
|
// .configure(|cfg: &mut web::ServiceConfig| {
|
||||||
|
@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
|
pub meta: String,
|
||||||
pub contents: String,
|
pub contents: String,
|
||||||
pub views: Option<u8>,
|
pub views: Option<u8>,
|
||||||
pub expiration: Option<u64>,
|
pub expiration: Option<u64>,
|
||||||
@ -14,6 +15,7 @@ pub struct NoteInfo {}
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct NotePublic {
|
pub struct NotePublic {
|
||||||
|
pub meta: String,
|
||||||
pub contents: String,
|
pub contents: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +96,7 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
|
|||||||
}
|
}
|
||||||
return HttpResponse::Ok().json(NotePublic {
|
return HttpResponse::Ok().json(NotePublic {
|
||||||
contents: changed.contents,
|
contents: changed.contents,
|
||||||
|
meta: changed.meta,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user