Skip to content

Commit

Permalink
set search contract
Browse files Browse the repository at this point in the history
  • Loading branch information
querwurzel committed Nov 8, 2023
1 parent b3849d8 commit 54fe6c4
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.github.binpastes.paste.api.model.CreateCmd;
import com.github.binpastes.paste.api.model.ListView;
import com.github.binpastes.paste.api.model.SearchView;
import com.github.binpastes.paste.api.model.SearchView.SearchItemView;
import com.github.binpastes.paste.api.model.SingleView;
import com.github.binpastes.paste.domain.Paste;
import com.github.binpastes.paste.domain.PasteService;
Expand Down Expand Up @@ -61,26 +63,26 @@ public Mono<SingleView> findPaste(@PathVariable("pasteId") String pasteId, Serve
response.getHeaders().add(HttpHeaders.CACHE_CONTROL, "max-age=300");
}
})
.map(reference -> SingleView.from(reference, remoteAddress(request)))
.map(reference -> SingleView.of(reference, remoteAddress(request)))
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND)));
}

@GetMapping
public Mono<ListView> findPastes() {
return pasteService
.findAll()
.map(ListItemView::from)
.map(ListItemView::of)
.collectList()
.map(ListView::from);
.map(ListView::of);
}

@GetMapping("/search")
public Mono<ListView> searchPastes(@RequestParam("term") @NotBlank @Size(min = 3) @Pattern(regexp = "[\\pL\\pN\\s]+") String term) {
public Mono<SearchView> searchPastes(@RequestParam("term") @NotBlank @Size(min = 3) @Pattern(regexp = "[\\pL\\pN\\s]+") String term) {
return pasteService
.findByFullText(term)
.map(ListItemView::from)
.map(paste -> SearchItemView.of(paste, term))
.collectList()
.map(ListView::from);
.map(SearchView::of);
}

@PostMapping
Expand All @@ -95,7 +97,7 @@ public Mono<SingleView> createPaste(@Valid @RequestBody Mono<CreateCmd> createCm
cmd.pasteExposure(),
remoteAddress(request)
))
.map((Paste reference) -> SingleView.from(reference, remoteAddress(request)));
.map((Paste reference) -> SingleView.of(reference, remoteAddress(request)));
}

@DeleteMapping("/{pasteId:[a-zA-Z0-9]{40}}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
public record ListView(
List<ListItemView> pastes
) {
public static ListView from(List<ListItemView> pastes) {
public static ListView of(final List<ListItemView> pastes) {
return new ListView(pastes);
}

Expand All @@ -20,7 +20,7 @@ public record ListItemView (
LocalDateTime dateCreated,
LocalDateTime dateOfExpiry
) {
public static ListItemView from(Paste reference) {
public static ListItemView of(final Paste reference) {
return new ListItemView(
reference.getId(),
reference.getTitle(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.github.binpastes.paste.api.model;

import com.github.binpastes.paste.domain.Paste;

import java.time.LocalDateTime;
import java.util.List;

public record SearchView(
List<SearchItemView> pastes
) {

public static SearchView of(List<SearchItemView> pastes) {
return new SearchView(pastes);
}

public record SearchItemView(
String id,
String title,
String highlight,
int sizeInBytes,
LocalDateTime dateCreated,
LocalDateTime dateOfExpiry
) {

private static final short HIGHLIGHT_RANGE = 25;

public static SearchItemView of(final Paste reference, final String term) {
return new SearchItemView(
reference.getId(),
reference.getTitle(),
highlight(reference.getContent(), term),
reference.getContent().getBytes().length,
reference.getDateCreated(),
reference.getDateOfExpiry()
);
}

public static String highlight(final String content, final String term) {
final int idx = content.indexOf(term);

if (idx == -1) {
return content;
}

return content.substring(
Math.max(0, idx - HIGHLIGHT_RANGE),
Math.min(content.length(), idx + term.length() + HIGHLIGHT_RANGE)
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public record SingleView(
LocalDateTime lastViewed,
long views
) {
public static SingleView from(Paste reference, String remoteAddress) {
public static SingleView of(final Paste reference, final String remoteAddress) {
return new SingleView(
reference.getId(),
reference.getTitle(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public Flux<Paste> searchByFullText(final String text) {
.or(PasteSchema.DATE_OF_EXPIRY).greaterThan(LocalDateTime.now())
)
.and(Criteria
.where(PasteSchema.TITLE).like(text + '%')
.where(PasteSchema.TITLE).like('%' + text + '%')
.or(Criteria
.where(PasteSchema.CONTENT).like(text + '%')
.where(PasteSchema.CONTENT).like('%' + text + '%')
.and(PasteSchema.IS_ENCRYPTED).isFalse()
)
);
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/api/client.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {PasteCreateCmd} from './model/PasteCreateCmd';
import {PasteListView} from './model/PasteListView';
import {PasteView} from './model/PasteView';
import {PasteSearchView} from './model/PasteSearchView';

const HOST_DEVELOPMENT = 'localhost:3000';

Expand Down Expand Up @@ -53,7 +54,7 @@ const findAll = (): Promise<Array<PasteListView>> => {
.then(value => value.pastes);
}

const searchAll = (term: string): Promise<Array<PasteListView>> => {
const searchAll = (term: string): Promise<Array<PasteSearchView>> => {
const params = new URLSearchParams([['term', term]]);
const url = new URL('/api/v1/paste/search?' + params.toString(), apiBaseUrl());

Expand Down
4 changes: 0 additions & 4 deletions frontend/src/api/model/PasteListView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,3 @@ export type PasteListView = {
dateCreated: string
dateOfExpiry?: string
}

export type = PasteList {
pastes: Array<PasteListView>
}
9 changes: 9 additions & 0 deletions frontend/src/api/model/PasteSearchView.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

export type PasteSearchView = {
id: string
title?: string
highlight: string
sizeInBytes: number
dateCreated: string
dateOfExpiry?: string
}
28 changes: 27 additions & 1 deletion frontend/src/pages/Search.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
import {JSX} from 'solid-js';
import {JSX, createResource} from 'solid-js';
import {A, useNavigate, useLocation} from '@solidjs/router';
import ApiClient from '../api/client';
import {toDateTimeString} from '../datetime/DateTimeUtil';

const Search: () => JSX.Element = () => {

const navigate = useNavigate();

const location = useLocation();

const [pastes, { mutate, refetch }] = createResource(() => location.query.q, (term) => ApiClient.searchAll(term));

return (
<>
<h2>Search</h2>
<Show when={pastes() && pastes().length} keyed fallback={<p>Nothing found</p>}>
<ol>
<For each={pastes()}>{item =>
<li>
<p><A href={'/paste/' + item.id}>{item.title || 'Untitled' }</A></p>
<p>
Created: <time>{toDateTimeString(item.dateCreated)}</time> |
Expires: <time>{item.dateOfExpiry ? toDateTimeString(item.dateOfExpiry) : 'Never'}</time> |
Size: {item.sizeInBytes} bytes
</p>
<pre>{item.content}</pre>
</li>
}
</For>
</ol>
</Show>
</>
)
}
Expand Down

0 comments on commit 54fe6c4

Please sign in to comment.