Compare commits
No commits in common. "d920f5b9b9c80c8c32df17d2dfe45b97d40269ae" and "0fae2e407ca31eacc4cd84851dbd8e1e09b080ed" have entirely different histories.
d920f5b9b9
...
0fae2e407c
|
@ -6,28 +6,12 @@ use crate::{
|
||||||
models::feed::new_feed::NewFeed, schema::feed,
|
models::feed::new_feed::NewFeed, schema::feed,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::feeds;
|
|
||||||
|
|
||||||
pub async fn add(new_feed: web::Json<NewFeedSchema>) -> HttpResponse {
|
pub async fn add(new_feed: web::Json<NewFeedSchema>) -> HttpResponse {
|
||||||
let mut connection = establish_connection();
|
let mut connection = establish_connection();
|
||||||
let title: String = new_feed.title.clone();
|
let title: String = new_feed.title.clone();
|
||||||
let url: String = new_feed.url.clone();
|
let url: String = new_feed.url.clone();
|
||||||
let user_id: i32 = new_feed.user_id;
|
let user_id: i32 = new_feed.user_id;
|
||||||
|
|
||||||
let result = feeds::get_feed(&url).await;
|
|
||||||
match result {
|
|
||||||
Ok(channel) => {
|
|
||||||
log::info!("valid channel");
|
|
||||||
if channel.items.is_empty() {
|
|
||||||
return HttpResponse::ServiceUnavailable().await.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("{:?}", e);
|
|
||||||
return HttpResponse::NotFound().await.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_feed = NewFeed::new(title, url, user_id);
|
let new_feed = NewFeed::new(title, url, user_id);
|
||||||
|
|
||||||
let insert_result = diesel::insert_into(feed::table)
|
let insert_result = diesel::insert_into(feed::table)
|
||||||
|
|
|
@ -19,8 +19,7 @@ use scraper::{Html, Selector};
|
||||||
|
|
||||||
fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||||
let item_title = item.title.clone().unwrap();
|
let item_title = item.title.clone().unwrap();
|
||||||
log::info!("Create feed item: {}", item_title);
|
let frag = Html::parse_fragment(&item.content.clone().unwrap());
|
||||||
let frag = Html::parse_fragment(&item.content.clone().unwrap_or_default());
|
|
||||||
let mut content = "".to_string();
|
let mut content = "".to_string();
|
||||||
let frag_clone = frag.clone();
|
let frag_clone = frag.clone();
|
||||||
frag.tree.into_iter().for_each(|node| {
|
frag.tree.into_iter().for_each(|node| {
|
||||||
|
@ -42,19 +41,13 @@ fn create_feed_item(item: Item, feed: &Feed, connection: &mut PgConnection) {
|
||||||
.filter(title.eq(&item_title))
|
.filter(title.eq(&item_title))
|
||||||
.load(connection)
|
.load(connection)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
// todo;
|
||||||
if existing_item.is_empty() {
|
if existing_item.is_empty() {
|
||||||
log::info!("{:?}", item.pub_date());
|
log::info!("{:?}", item.pub_date());
|
||||||
let mut time: NaiveDateTime = Local::now().naive_local();
|
let mut time: NaiveDateTime = Local::now().naive_local();
|
||||||
if item.pub_date().is_some() {
|
if item.pub_date().is_some() {
|
||||||
let format_string = "%a, %d %b %Y %H:%M:%S %z";
|
let format_string = "%a, %d %b %Y %H:%M:%S %z";
|
||||||
time = match NaiveDateTime::parse_from_str(item.pub_date().unwrap(), format_string) {
|
time = NaiveDateTime::parse_from_str(item.pub_date().unwrap(), format_string).unwrap();
|
||||||
Ok(date) => date,
|
|
||||||
Err(err) => {
|
|
||||||
log::error!("could not unwrap pub date: {}", err);
|
|
||||||
time
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let new_feed_item = NewFeedItem::new(
|
let new_feed_item = NewFeedItem::new(
|
||||||
feed.id,
|
feed.id,
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
import { ref, unref, onMounted, nextTick } from 'vue';
|
import { ref, unref, onMounted, nextTick } from 'vue';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Readability } from '@mozilla/readability';
|
import { Readability } from '@mozilla/readability';
|
||||||
import Modal from './modal/AddUrl.vue';
|
|
||||||
|
|
||||||
const showMessage = ref(false)
|
const showMessage = ref(false)
|
||||||
const feeds = ref([]);
|
const feeds = ref([]);
|
||||||
const message = ref('')
|
const message = ref('')
|
||||||
const showModal = ref(false)
|
const buttonText = 'Sync'
|
||||||
|
|
||||||
async function getReadable(feed, index) {
|
async function getReadable(feed, index) {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post("feeds/read", {
|
const response = await axios.post("feeds/read", {
|
||||||
|
@ -67,9 +65,7 @@ const fetchData = async () => {
|
||||||
'user-token': localStorage.getItem("user-token")
|
'user-token': localStorage.getItem("user-token")
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
response.data.feeds.forEach(feed => {
|
feeds.value = response.data.feeds[0].items;
|
||||||
feeds.value.push(...feed.items);
|
|
||||||
});
|
|
||||||
await nextTick();
|
await nextTick();
|
||||||
setupIntersectionObserver();
|
setupIntersectionObserver();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -157,28 +153,18 @@ onMounted(() => {
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<nav>
|
<nav>
|
||||||
<p @click="sync">Sync</p>
|
<p @click="sync">Sync</p>
|
||||||
<!-- <p @click="updateShow(true)">Add RSS</p> -->
|
|
||||||
<p @click="showModal = true">Add RSS</p>
|
|
||||||
<!-- <RouterLink to="/">Home</RouterLink> -->
|
<!-- <RouterLink to="/">Home</RouterLink> -->
|
||||||
<!-- <RouterLink to="/about">About</RouterLink> -->
|
<!-- <RouterLink to="/about">About</RouterLink> -->
|
||||||
<!-- <RouterLink to="/feeds">Feeds</RouterLink> -->
|
<!-- <RouterLink to="/feeds">Feeds</RouterLink> -->
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<Teleport to="body">
|
|
||||||
<!-- use the modal component, pass in the prop -->
|
|
||||||
<modal :show="showModal" @close="showModal = false">
|
|
||||||
<template #header>
|
|
||||||
<h3>Add RSS Feed</h3>
|
|
||||||
</template>
|
|
||||||
</modal>
|
|
||||||
</Teleport>
|
|
||||||
<div>
|
<div>
|
||||||
<h1>Feeds</h1> <!-- <button @click="sync">{{ buttonText }}</button> -->
|
<h1>Feeds</h1> <!-- <button @click="sync">{{ buttonText }}</button> -->
|
||||||
<div v-if="showMessage" class="message">{{ message }}</div>
|
<div v-if="showMessage" class="message">{{ message }}</div>
|
||||||
<div id='article' class='article'>
|
<div id='article' class='article'>
|
||||||
<p v-if="feeds.length == 0">No unread articles.</p>
|
<p v-if="feeds.length == 0">No unread articles.</p>
|
||||||
<template v-for="( feed, index ) in feeds ">
|
<template v-for="(feed, index) in feeds">
|
||||||
<div v-bind:id="index" class="observe">
|
<div v-bind:id="index" class="observe">
|
||||||
<h2 @click="getReadable(feed, index)" class="feed-title">{{ feed.title }}</h2>
|
<h2 @click="getReadable(feed, index)" class="feed-title">{{ feed.title }}</h2>
|
||||||
<p class="feed-content" v-html='feed.content'></p>
|
<p class="feed-content" v-html='feed.content'></p>
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import axios from 'axios';
|
|
||||||
const props = defineProps({
|
|
||||||
show: Boolean
|
|
||||||
})
|
|
||||||
const submitted = ref(false)
|
|
||||||
const url = ref('')
|
|
||||||
const title = ref('')
|
|
||||||
const output = ref('')
|
|
||||||
|
|
||||||
async function save() {
|
|
||||||
output.value = ''
|
|
||||||
submitted.value = true;
|
|
||||||
console.log('saved ' + url.value)
|
|
||||||
try {
|
|
||||||
const response = await axios.post("feeds/add", {
|
|
||||||
url: url.value,
|
|
||||||
title: title.value,
|
|
||||||
user_id: parseInt(localStorage.getItem("user-id"))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
'user-token': localStorage.getItem("user-token")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
console.log(response)
|
|
||||||
output.value = 'saved successfully'
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error.message)
|
|
||||||
output.value = error.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<Transition name="modal">
|
|
||||||
<div v-if="show" class="modal-mask">
|
|
||||||
<div class="modal-container">
|
|
||||||
<div class="modal-header">
|
|
||||||
<slot name="header">Add RSS Feed</slot>
|
|
||||||
</div>
|
|
||||||
<form @submit.prevent="submitForm">
|
|
||||||
<label for="name">URL:</label>
|
|
||||||
<input v-model="url" id="url" type="text" required />
|
|
||||||
<label for="name">Title:</label>
|
|
||||||
<input v-model="title" id="title" type="text" required />
|
|
||||||
|
|
||||||
<div v-if="submitted">
|
|
||||||
<p>{{ output }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<slot name="footer">
|
|
||||||
<button type="submit" @click="save">Save</button>
|
|
||||||
<button class="modal-default-button" @click="$emit('close')">Close</button>
|
|
||||||
</slot>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Transition>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
input {
|
|
||||||
margin: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-mask {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 9998;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-container {
|
|
||||||
width: 300px;
|
|
||||||
margin: auto;
|
|
||||||
padding: 20px 30px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 2px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-header h3 {
|
|
||||||
margin-top: 0;
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-default-button {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following styles are auto-applied to elements with
|
|
||||||
* transition="modal" when their visibility is toggled
|
|
||||||
* by Vue.js.
|
|
||||||
*
|
|
||||||
* You can easily play with the modal transition by editing
|
|
||||||
* these styles.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.modal-enter-from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-leave-to {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-enter-from .modal-container,
|
|
||||||
.modal-leave-to .modal-container {
|
|
||||||
-webkit-transform: scale(1.1);
|
|
||||||
transform: scale(1.1);
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -40,12 +40,6 @@ export default defineConfig({
|
||||||
secure: false,
|
secure: false,
|
||||||
rewrite: (path) => path.replace(/^\/feeds\/read/, ''),
|
rewrite: (path) => path.replace(/^\/feeds\/read/, ''),
|
||||||
},
|
},
|
||||||
'/feeds/add': {
|
|
||||||
target: 'http://localhost:8001/api/v1/article/add',
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
rewrite: (path) => path.replace(/^\/feeds\/add/, ''),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cors: false
|
cors: false
|
||||||
|
|
Loading…
Reference in New Issue