fixed
This commit is contained in:
parent
43011c1509
commit
dadbfde802
1
init.sql
1
init.sql
@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS public.entries
|
||||
paragraph text COLLATE pg_catalog."default",
|
||||
time_published timestamp without time zone NOT NULL,
|
||||
filepath text COLLATE pg_catalog."default",
|
||||
group_name text COLLATE pg_catalog."default",
|
||||
CONSTRAINT entries_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
|
||||
@ -31,7 +31,8 @@ public class SecurityConfig {
|
||||
|
||||
return http.csrf(customizer -> customizer.disable()).
|
||||
authorizeHttpRequests(request -> request
|
||||
.requestMatchers("login", "register").permitAll()
|
||||
.requestMatchers("/login", "/register").permitAll()
|
||||
.requestMatchers("/subject/**", "/entries", "/groups").permitAll()
|
||||
.anyRequest().authenticated()).
|
||||
httpBasic(Customizer.withDefaults()).
|
||||
sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
|
||||
@ -6,39 +6,56 @@ import dev.ksan.etfoglasiserver.service.EntryService;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
public class EntryController {
|
||||
@Autowired EntryService service;
|
||||
|
||||
@GetMapping("/entry")
|
||||
public List<Entry> getEntries() {
|
||||
return service.getEntries();
|
||||
}
|
||||
// @GetMapping("/entries")
|
||||
// public List<Entry> getEntries() {
|
||||
// return service.getEntries();
|
||||
// }
|
||||
|
||||
@GetMapping("/entry/{entryId}")
|
||||
@GetMapping("/entries/{entryId}")
|
||||
public Entry getEntry(@PathVariable String entryId) {
|
||||
return service.getEntryById(entryId);
|
||||
}
|
||||
|
||||
@PostMapping("/entry")
|
||||
//ignore this for now
|
||||
@PostMapping("/entries")
|
||||
public void addEntry(@RequestBody EntryDTO entry) {
|
||||
service.addEntry(entry);
|
||||
}
|
||||
|
||||
@PutMapping("/entry")
|
||||
|
||||
@GetMapping("/groups")
|
||||
public List<String> getGroups() {
|
||||
return service.getAllGroups();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/entries")
|
||||
public Page<Entry> getEntries(
|
||||
@RequestParam(required = false) String subjectId,
|
||||
@RequestParam(required = false) String groupName,
|
||||
@RequestParam(defaultValue = "0") int page
|
||||
) {
|
||||
UUID parsedSubjectId = subjectId != null ? UUID.fromString(subjectId) : null;
|
||||
return service.getEntries(parsedSubjectId, groupName, page);
|
||||
}
|
||||
|
||||
@PutMapping("/entries")
|
||||
public void updateEntry(@RequestBody EntryDTO entry) {
|
||||
service.updateEntry(entry);
|
||||
}
|
||||
|
||||
@DeleteMapping("/entry/{entryId}")
|
||||
@DeleteMapping("/entries/{entryId}")
|
||||
public void deleteEntry(@PathVariable String entryId) {
|
||||
service.deleteEntry(entryId);
|
||||
}
|
||||
|
||||
@ -47,14 +47,7 @@ public class UserController {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
/*
|
||||
@PostMapping("/users")
|
||||
public void addUser(@RequestBody UserCreationDTO user) {
|
||||
NotificationMethod method = NotificationMethod.valueOf(user.getNotification());
|
||||
user.setNotificationMethod(method);
|
||||
service.addUser(user);
|
||||
}
|
||||
*/
|
||||
|
||||
@PostMapping("/login")
|
||||
public ResponseEntity<JwtResponseDTO> login(@RequestBody UserLoginDTO user) {
|
||||
JwtResponseDTO userVer = service.verify(user);
|
||||
@ -75,4 +68,13 @@ public class UserController {
|
||||
public void deleteUser(@PathVariable UUID userId) {
|
||||
service.deleteUser(userId);
|
||||
}
|
||||
|
||||
/*
|
||||
@PostMapping("/users")
|
||||
public void addUser(@RequestBody UserCreationDTO user) {
|
||||
NotificationMethod method = NotificationMethod.valueOf(user.getNotification());
|
||||
user.setNotificationMethod(method);
|
||||
service.addUser(user);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@ -6,8 +6,9 @@ import java.util.UUID;
|
||||
|
||||
public class EntryDTO {
|
||||
|
||||
private String id;
|
||||
private UUID id;
|
||||
private String title;
|
||||
private String group;
|
||||
private LocalDateTime time_published;
|
||||
private String info_entry;
|
||||
private String paragraph;
|
||||
@ -15,8 +16,9 @@ public class EntryDTO {
|
||||
private UUID subjectId;
|
||||
|
||||
public EntryDTO() {}
|
||||
public EntryDTO( String title, LocalDateTime time_published, String info_entry, String paragraph, String filepath, UUID subjectId) {
|
||||
public EntryDTO( String title, String group, LocalDateTime time_published, String info_entry, String paragraph, String filepath, UUID subjectId) {
|
||||
this.title = title;
|
||||
this.group = group;
|
||||
this.time_published = time_published;
|
||||
this.info_entry = info_entry;
|
||||
this.paragraph = paragraph;
|
||||
@ -38,11 +40,11 @@ public class EntryDTO {
|
||||
return subjectId;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
public void setSubjectId(UUID subjectId) {
|
||||
@ -92,4 +94,12 @@ public class EntryDTO {
|
||||
public void setFilepath(String filepath) {
|
||||
this.filepath = filepath;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.group = group;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package dev.ksan.etfoglasiserver.model;
|
||||
import dev.ksan.etfoglasiserver.dto.EntryDTO;
|
||||
import dev.ksan.etfoglasiserver.util.HashGenerator;
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
@ -10,14 +11,23 @@ import java.util.UUID;
|
||||
@Entity
|
||||
@Table(name = "entries")
|
||||
public class Entry {
|
||||
@Id private String id;
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Column(columnDefinition = "uuid", updatable = false, nullable = false)
|
||||
private UUID id;
|
||||
|
||||
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
@JoinColumn(nullable = false)
|
||||
private Subject subject;
|
||||
|
||||
@Column private String title;
|
||||
@Column private LocalDateTime time_published;
|
||||
@Column(name = "time_published")
|
||||
private LocalDateTime timePublished;
|
||||
|
||||
@Column(name = "group_name")
|
||||
private String groupName;
|
||||
|
||||
private String info_entry;
|
||||
private String paragraph;
|
||||
private String filepath;
|
||||
@ -31,7 +41,7 @@ public class Entry {
|
||||
String paragraph,
|
||||
String filepath) {
|
||||
this.title = title;
|
||||
this.time_published = time_published;
|
||||
this.timePublished= time_published;
|
||||
this.info_entry = info_entry;
|
||||
this.paragraph = paragraph;
|
||||
this.filepath = filepath;
|
||||
@ -44,14 +54,15 @@ public class Entry {
|
||||
List<String> paragraph,
|
||||
String filepath) {
|
||||
this.title = title;
|
||||
this.time_published = time_published;
|
||||
this.timePublished= time_published;
|
||||
this.info_entry = info_entry;
|
||||
this.paragraph = String.join("\n", paragraph);
|
||||
this.filepath = filepath;
|
||||
}
|
||||
public Entry( String title, LocalDateTime time_published, String info_entry, List<String> paragraphs, String filepath, Subject subjectId) {
|
||||
public Entry( String title,String group, LocalDateTime time_published, String info_entry, List<String> paragraphs, String filepath, Subject subjectId) {
|
||||
this.title = title;
|
||||
this.time_published = time_published;
|
||||
this.groupName = group;
|
||||
this.timePublished= time_published;
|
||||
this.info_entry = info_entry;
|
||||
this.paragraph = String.join("\n",paragraphs);
|
||||
this.filepath = filepath;
|
||||
@ -63,16 +74,7 @@ public class Entry {
|
||||
this.paragraph = entry.getParagraph();
|
||||
this.info_entry = entry.getInfo_entry();
|
||||
this.filepath = entry.getFilepath();
|
||||
this.time_published = entry.getTime_published();
|
||||
}
|
||||
|
||||
@PrePersist
|
||||
public void generateId() {
|
||||
|
||||
if (this.id == null) {
|
||||
|
||||
this.id = HashGenerator.hashEntry(this);
|
||||
}
|
||||
this.timePublished= entry.getTime_published();
|
||||
}
|
||||
|
||||
public String getParagraph() {
|
||||
@ -103,21 +105,23 @@ public class Entry {
|
||||
return title;
|
||||
}
|
||||
|
||||
public LocalDateTime getDate() {
|
||||
return time_published;
|
||||
public LocalDateTime getTimePublished() {
|
||||
return timePublished;
|
||||
}
|
||||
|
||||
public String getInfo() {
|
||||
return info_entry;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null) return false;
|
||||
Entry subject = (Entry) o;
|
||||
if (title.equals(subject.getTitle())
|
||||
&& time_published.equals(subject.getDate())
|
||||
&& timePublished.equals(subject.getTimePublished())
|
||||
&& info_entry.equals(subject.getInfo())) {
|
||||
return true;
|
||||
}
|
||||
@ -135,7 +139,7 @@ public class Entry {
|
||||
+ title
|
||||
+ '\''
|
||||
+ ", time_published="
|
||||
+ time_published
|
||||
+ timePublished
|
||||
+ ", info_entry='"
|
||||
+ info_entry
|
||||
+ '\''
|
||||
@ -161,6 +165,14 @@ public class Entry {
|
||||
}
|
||||
|
||||
public void setTime_published(LocalDateTime timePublished) {
|
||||
this.time_published = timePublished;
|
||||
this.timePublished= timePublished;
|
||||
}
|
||||
|
||||
public String getGroup() {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
public void setGroup(String group) {
|
||||
this.groupName = group;
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ public class Subject {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(columnDefinition = "uuid")
|
||||
private UUID id;
|
||||
|
||||
@Column private long code;
|
||||
@ -18,6 +19,8 @@ public class Subject {
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
|
||||
|
||||
@ManyToMany(mappedBy = "subjectSet", fetch = FetchType.LAZY)
|
||||
Set<User> users;
|
||||
public Subject(){
|
||||
|
||||
@ -1,9 +1,25 @@
|
||||
package dev.ksan.etfoglasiserver.repository;
|
||||
|
||||
import dev.ksan.etfoglasiserver.model.Entry;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import dev.ksan.etfoglasiserver.model.Subject;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
public interface EntryRepo extends JpaRepository<Entry, String> {}
|
||||
public interface EntryRepo extends JpaRepository<Entry, String> {
|
||||
|
||||
Optional<Entry> findByTitleAndTimePublishedAndSubject(String title, LocalDateTime timePublished, Subject subject);
|
||||
|
||||
Page<Entry> findAllByOrderByTimePublishedDesc(Pageable pageable);
|
||||
Page<Entry> findBySubjectOrderByTimePublishedDesc(Subject subject, Pageable pageable);
|
||||
Page<Entry> findByGroupNameOrderByTimePublishedDesc(String groupName, Pageable pageable);
|
||||
Page<Entry> findBySubjectAndGroupNameOrderByTimePublishedDesc(Subject subject, String groupName, Pageable pageable);
|
||||
}
|
||||
|
||||
|
||||
@ -6,16 +6,26 @@ import dev.ksan.etfoglasiserver.model.Subject;
|
||||
import dev.ksan.etfoglasiserver.repository.EntryRepo;
|
||||
import dev.ksan.etfoglasiserver.repository.SubjectRepo;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@Service
|
||||
public class EntryService {
|
||||
|
||||
@Autowired EntryRepo entryRepo;
|
||||
@Autowired
|
||||
EntryRepo entryRepo;
|
||||
|
||||
@Autowired SubjectService subjectService;
|
||||
@Autowired
|
||||
SubjectService subjectService;
|
||||
|
||||
public List<Entry> getEntries() {
|
||||
return entryRepo.findAll();
|
||||
@ -34,12 +44,22 @@ public class EntryService {
|
||||
newEntry.setSubject(subject);
|
||||
entryRepo.save(newEntry);
|
||||
}
|
||||
public void addEntry(Entry entry) {
|
||||
|
||||
public void addEntry(Entry entry) {
|
||||
Optional<Entry> existing = entryRepo.findByTitleAndTimePublishedAndSubject(
|
||||
entry.getTitle(),
|
||||
entry.getTimePublished(),
|
||||
entry.getSubject()
|
||||
);
|
||||
|
||||
if (existing.isPresent()) {
|
||||
System.out.println("Duplicate entry, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
entryRepo.save(entry);
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
System.out.println("Duplicate");
|
||||
return;
|
||||
}
|
||||
@ -50,7 +70,7 @@ public class EntryService {
|
||||
Subject subject =
|
||||
subjectService
|
||||
.findById(entry.getSubjectId());
|
||||
Entry updateEntry = entryRepo.findById(entry.getId()).orElseThrow(() -> new RuntimeException("Entry not found"));
|
||||
Entry updateEntry = entryRepo.findById(entry.getId().toString()).orElseThrow(() -> new RuntimeException("Entry not found"));
|
||||
updateEntry.setSubject(subject);
|
||||
if (entry.getTitle() != null) {
|
||||
updateEntry.setTitle(entry.getTitle());
|
||||
@ -73,4 +93,35 @@ public class EntryService {
|
||||
public void deleteEntry(String id) {
|
||||
entryRepo.deleteById(id);
|
||||
}
|
||||
|
||||
|
||||
public Page<Entry> getEntries(UUID subjectId, String groupName, int page) {
|
||||
Pageable pageable = PageRequest.of(page, 20, Sort.by("timePublished").descending());
|
||||
|
||||
if (subjectId != null && groupName != null) {
|
||||
Subject subject = subjectService.findById(subjectId);
|
||||
return entryRepo.findBySubjectAndGroupNameOrderByTimePublishedDesc(subject, groupName, pageable);
|
||||
}
|
||||
if (subjectId != null) {
|
||||
Subject subject = subjectService.findById(subjectId);
|
||||
return entryRepo.findBySubjectOrderByTimePublishedDesc(subject, pageable);
|
||||
}
|
||||
if (groupName != null) {
|
||||
return entryRepo.findByGroupNameOrderByTimePublishedDesc(groupName, pageable);
|
||||
}
|
||||
|
||||
return entryRepo.findAllByOrderByTimePublishedDesc(pageable);
|
||||
}
|
||||
|
||||
public List<String> getAllGroups() {
|
||||
List<Entry> allEntries = entryRepo.findAll();
|
||||
|
||||
// Extract unique group names
|
||||
return allEntries.stream()
|
||||
.map(Entry::getGroup)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,10 +2,7 @@ package dev.ksan.etfoglasiserver.service;
|
||||
|
||||
import com.gargoylesoftware.htmlunit.BrowserVersion;
|
||||
import com.gargoylesoftware.htmlunit.WebClient;
|
||||
import com.gargoylesoftware.htmlunit.html.DomElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlAnchor;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlElement;
|
||||
import com.gargoylesoftware.htmlunit.html.HtmlPage;
|
||||
import com.gargoylesoftware.htmlunit.html.*;
|
||||
import dev.ksan.etfoglasiserver.dto.EntryDTO;
|
||||
import dev.ksan.etfoglasiserver.model.Entry;
|
||||
import java.time.LocalDateTime;
|
||||
@ -74,8 +71,23 @@ public class Scraper implements Runnable {
|
||||
}
|
||||
int ul_idSelection = 1;
|
||||
for (HtmlAnchor anchor : toggles) {
|
||||
String groupName = anchor.asNormalizedText().split("\n")[0].trim();
|
||||
// System.out.println("Group name: " + groupName);
|
||||
HtmlElement span = anchor.getFirstByXPath(".//span[@class='ui-btn-text']");
|
||||
if (span == null) continue; // skip anchors with no text span
|
||||
|
||||
// Skip “clear text” buttons
|
||||
String spanText = span.asNormalizedText().toLowerCase();
|
||||
if (spanText.contains("clear text")) continue;
|
||||
|
||||
// Only get direct text nodes (skip child span with collapse text)
|
||||
List<DomText> textNodes = span.getByXPath("./text()");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (DomText textNode : textNodes) {
|
||||
sb.append(textNode.asNormalizedText());
|
||||
}
|
||||
String groupName = sb.toString().trim();
|
||||
|
||||
System.out.println("Group name: " + groupName);
|
||||
|
||||
HtmlPage updatedPage = anchor.click();
|
||||
webClient.waitForBackgroundJavaScript(1000);
|
||||
|
||||
@ -98,15 +110,25 @@ public class Scraper implements Runnable {
|
||||
String info = getTextOrEmpty(item, ".//h2[2]");
|
||||
List<String> paragraphs = new ArrayList<>();
|
||||
List<HtmlElement> pTags = item.getByXPath(".//p");
|
||||
String filepath = null; // default
|
||||
for (HtmlElement pTag : pTags) {
|
||||
paragraphs.add(pTag.asNormalizedText());
|
||||
|
||||
// check if this <p> contains an <a> link
|
||||
HtmlAnchor aTag = pTag.getFirstByXPath(".//a");
|
||||
if (aTag != null) {
|
||||
filepath = aTag.getHrefAttribute();
|
||||
}
|
||||
// Entry entry = new Entry(title, groupName, date, info, paragraphs);
|
||||
}
|
||||
|
||||
Subject subjectid = altService.findSubjectIdWithTitle(title);
|
||||
Entry entry =
|
||||
new Entry(
|
||||
title.trim(), LocalDateTime.parse(date, formatter), info, paragraphs, null, subjectid);
|
||||
title.trim(), groupName, LocalDateTime.parse(date, formatter),
|
||||
info, paragraphs, filepath, subjectid);
|
||||
|
||||
System.out.println("Subject "+entry.getTitle());
|
||||
System.out.println();
|
||||
|
||||
|
||||
entryService.addEntry(entry);
|
||||
@ -115,7 +137,7 @@ public class Scraper implements Runnable {
|
||||
ul_idSelection++;
|
||||
}
|
||||
|
||||
// Thread.sleep(20000);
|
||||
Thread.sleep(300000);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -10,7 +10,7 @@ public class HashGenerator {
|
||||
public static String hashEntry(Entry entry) {
|
||||
String data =
|
||||
Objects.toString(entry.getTitle(), "")
|
||||
+ Objects.toString(entry.getDate(), "")
|
||||
+ Objects.toString(entry.getTimePublished(), "")
|
||||
+ Objects.toString(entry.getParagraph(), "")
|
||||
+ Objects.toString(entry.getFilepath(), "");
|
||||
|
||||
|
||||
@ -2,3 +2,4 @@ spring.application.name=etfoglasi-server
|
||||
spring.datasource.url=jdbc:postgresql://localhost:5432/etfo-db
|
||||
spring.datasource.username=test
|
||||
spring.datasource.password=test
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user