Compare commits
2 Commits
05152cd5a4
...
8833a213a7
Author | SHA1 | Date | |
---|---|---|---|
|
8833a213a7 | ||
|
f833845452 |
@ -27,10 +27,17 @@ export default {
|
|||||||
},
|
},
|
||||||
beforeCreate: function(){
|
beforeCreate: function(){
|
||||||
|
|
||||||
|
//Puts token into state on page load
|
||||||
|
let token = localStorage.getItem('loginToken')
|
||||||
|
let username = localStorage.getItem('username')
|
||||||
|
|
||||||
// const socket = io({ path:'/socket' });
|
// const socket = io({ path:'/socket' });
|
||||||
const socket = this.$io
|
const socket = this.$io
|
||||||
socket.on('connect', () => {
|
socket.on('connect', () => {
|
||||||
|
|
||||||
this.$store.commit('setSocketIoSocket', socket.id)
|
this.$store.commit('setSocketIoSocket', socket.id)
|
||||||
|
|
||||||
|
this.$io.emit('user_connect', token)
|
||||||
})
|
})
|
||||||
|
|
||||||
//Detect if user is on a mobile browser and set a flag in store
|
//Detect if user is on a mobile browser and set a flag in store
|
||||||
@ -41,16 +48,20 @@ export default {
|
|||||||
this.$store.commit('toggleNightMode')
|
this.$store.commit('toggleNightMode')
|
||||||
}
|
}
|
||||||
|
|
||||||
//Puts token into state on page load
|
//Put user data into global store on load
|
||||||
let token = localStorage.getItem('loginToken')
|
|
||||||
let username = localStorage.getItem('username')
|
|
||||||
|
|
||||||
if(token){
|
if(token){
|
||||||
this.$store.commit('setLoginToken', {token, username})
|
this.$store.commit('setLoginToken', {token, username})
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
mounted: function(){
|
mounted: function(){
|
||||||
|
|
||||||
|
//Update totals for entire app on event
|
||||||
|
this.$io.on('update_counts', () => {
|
||||||
|
console.log('Got event, update totals')
|
||||||
|
this.$store.dispatch('fetchAndUpdateUserTotals')
|
||||||
|
})
|
||||||
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
loggedIn () {
|
loggedIn () {
|
||||||
|
113
client/src/components/AnimatedCounterComponent.vue
Normal file
113
client/src/components/AnimatedCounterComponent.vue
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<style type="text/css" scoped>
|
||||||
|
|
||||||
|
.numtainer {
|
||||||
|
height: 1.1em;
|
||||||
|
font-size: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-high {
|
||||||
|
color: #4dc86a;
|
||||||
|
animation: startHigh 0.5s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-low {
|
||||||
|
color: #4dc86a;
|
||||||
|
animation: startLow 0.5s forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes startLow {
|
||||||
|
0% {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: -1.2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes startHigh {
|
||||||
|
0% {
|
||||||
|
margin-top: -1.2em;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="numtainer">
|
||||||
|
|
||||||
|
<div v-if="animateUp">
|
||||||
|
<div class="start-high">{{ newNumber }}</div>
|
||||||
|
<div>{{ oldNumber }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="animateDown">
|
||||||
|
<div class="start-low">{{ oldNumber }}</div>
|
||||||
|
<div>{{ newNumber }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div v-if="totals">{{ totals[numberId] }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AnimatedCounterComponent',
|
||||||
|
props: [ 'numberId' ],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
oldNumber: 100,
|
||||||
|
newNumber: 99,
|
||||||
|
animateUp: false,
|
||||||
|
animateDown: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters(['totals'])
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
totals(newVal, oldVal){
|
||||||
|
if(oldVal && newVal && newVal[this.numberId] != oldVal[this.numberId]){
|
||||||
|
|
||||||
|
console.log('New number ', newVal[this.numberId])
|
||||||
|
|
||||||
|
this.oldNumber = oldVal[this.numberId]
|
||||||
|
this.newNumber = newVal[this.numberId]
|
||||||
|
|
||||||
|
if(this.oldNumber > this.newNumber){
|
||||||
|
this.animateDown = true
|
||||||
|
} else {
|
||||||
|
this.animateUp = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
|
this.animateUp = false
|
||||||
|
this.animateDown = false
|
||||||
|
}, 550)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount(){
|
||||||
|
|
||||||
|
},
|
||||||
|
mounted(){
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFileClick(file){
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 0.8em 0px 0.8em 10px;
|
padding: 0.8em 10px 0.8em 10px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 1.15em;
|
font-size: 1.15em;
|
||||||
@ -111,7 +111,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="six wide center aligned column">
|
<div class="six wide center aligned column">
|
||||||
<img v-if="!loggedIn" src="/api/static/assets/favicon.ico" alt="logo" />
|
<img v-if="!loggedIn" src="/api/static/assets/favicon.ico" alt="logo" />
|
||||||
<search-input v-if="loggedIn"></search-input>
|
<search-input v-if="loggedIn && mobile"></search-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="three wide right aligned column">
|
<div class="three wide right aligned column">
|
||||||
|
|
||||||
@ -154,7 +154,7 @@
|
|||||||
<div class="menu-section" v-if="loggedIn">
|
<div class="menu-section" v-if="loggedIn">
|
||||||
<router-link exact-active-class="active" class="menu-item menu-button" to="/notes" v-on:click.native="emitReloadEvent()">
|
<router-link exact-active-class="active" class="menu-item menu-button" to="/notes" v-on:click.native="emitReloadEvent()">
|
||||||
<i class="file outline icon"></i>Notes
|
<i class="file outline icon"></i>Notes
|
||||||
<!-- <span v-if="$store.getters.totals">{{ $store.getters.totals['totalNotes'] }}</span> -->
|
<counter class="float-right" number-id="totalNotes" />
|
||||||
</router-link>
|
</router-link>
|
||||||
<div>
|
<div>
|
||||||
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
<!-- <div class="menu-item sub">Show Only <i class="caret down icon"></i></div> -->
|
||||||
@ -167,7 +167,7 @@
|
|||||||
<div class="menu-section" v-if="loggedIn && $store.getters.totals && $store.getters.totals['totalFiles']">
|
<div class="menu-section" v-if="loggedIn && $store.getters.totals && $store.getters.totals['totalFiles']">
|
||||||
<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
|
<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
|
||||||
<i class="folder open outline icon"></i>Files
|
<i class="folder open outline icon"></i>Files
|
||||||
<!-- <span>{{ $store.getters.totals['totalFiles'] }}</span> -->
|
<counter class="float-right" number-id="totalFiles" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -196,7 +196,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="menu-section" v-if="loggedIn">
|
<div class="menu-section" v-if="loggedIn" data-tooltip="Click to log out" data-inverted="" data-position="right center">
|
||||||
<div v-if="loggedIn" v-on:click="destroyLoginToken" class="menu-item menu-button">
|
<div v-if="loggedIn" v-on:click="destroyLoginToken" class="menu-item menu-button">
|
||||||
<i class="user outline icon"></i>{{ucWords($store.getters.getUsername)}}
|
<i class="user outline icon"></i>{{ucWords($store.getters.getUsername)}}
|
||||||
</div>
|
</div>
|
||||||
@ -216,6 +216,7 @@
|
|||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
'search-input': require('@/components/SearchInput.vue').default,
|
'search-input': require('@/components/SearchInput.vue').default,
|
||||||
|
'counter':require('@/components/AnimatedCounterComponent.vue').default,
|
||||||
},
|
},
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
<div class="sixteen wide column overflow-hidden note-card-text" @click="e => onClick(note.id, e)">
|
<div class="sixteen wide column overflow-hidden note-card-text" @click="e => onClick(note.id, e)">
|
||||||
|
|
||||||
|
<div class="subtext" v-if="note.shareUsername">Shared by {{ note.shareUsername }}</div>
|
||||||
|
<div class="subtext" v-if="note.shared == 2">You Shared</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- Title display -->
|
<!-- Title display -->
|
||||||
<div v-if="note.title.length > 0"
|
<div v-if="note.title.length > 0"
|
||||||
data-test-id="title"
|
data-test-id="title"
|
||||||
|
@ -3,19 +3,22 @@
|
|||||||
|
|
||||||
<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
|
<div class="ui grid" :class="{ 'mush-it-up':showOneColumn() }" ref="content">
|
||||||
|
|
||||||
<div v-if="!$store.getters.getIsUserOnMobile" class="sixteen wide column">
|
<div class="sixteen wide column">
|
||||||
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
<!-- :class="{ 'sixteen wide column':showOneColumn(), 'sixteen wide column':!showOneColumn() }" -->
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
|
|
||||||
<div class="eight wide column">
|
<div class="six wide column" v-if="!$store.getters.getIsUserOnMobile">
|
||||||
<search-input></search-input>
|
<search-input></search-input>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="eight wide column">
|
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
|
||||||
|
|
||||||
<div class="ui basic button" v-on:click="updateFastFilters(3)" v-if="$store.getters.totals && $store.getters.totals['sharedToNotes'] > 0" style="position: relative;">
|
<div class="ui basic button"
|
||||||
<i class="green mail icon"></i>Inbox
|
v-on:click="updateFastFilters(3)"
|
||||||
|
v-if="$store.getters.totals && ($store.getters.totals['sharedToNotes'] > 0 || $store.getters.totals['sharedFromNotes'] > 0)"
|
||||||
|
style="position: relative;">
|
||||||
|
<i class="green mail icon"></i>Shared Notes
|
||||||
<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
|
<span class="floating ui green label" v-if="$store.getters.totals['unreadNotes'] > 0">
|
||||||
{{ $store.getters.totals['unreadNotes'] }}
|
{{ $store.getters.totals['unreadNotes'] }}
|
||||||
</span>
|
</span>
|
||||||
@ -40,14 +43,11 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2 v-if="fastFilters['withLinks'] == 1">Notes with Links</h2>
|
||||||
|
<h2 v-if="fastFilters['withTags'] == 1">Notes with Tags</h2>
|
||||||
|
<h2 v-if="fastFilters['onlyArchived'] == 1">Archived Notes</h2>
|
||||||
|
<h2 v-if="fastFilters['onlyShowSharedNotes'] == 1">Shared Notes</h2>
|
||||||
|
|
||||||
<div v-if="$store.getters.getIsUserOnMobile && showClear" class="row">
|
|
||||||
<div class="sixteen wide column">
|
|
||||||
<span class="ui fluid green button" @click="reset">
|
|
||||||
<i class="arrow circle left icon"></i>Back to All Notes
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="commonTags.length > 0" class="sixteen wide column">
|
<div v-if="commonTags.length > 0" class="sixteen wide column">
|
||||||
<h4><i class="green tags icon"></i>Tags</h4>
|
<h4><i class="green tags icon"></i>Tags</h4>
|
||||||
@ -58,19 +58,17 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 v-if="fastFilters['withLinks'] == 1">Only showing notes containing Links</h2>
|
|
||||||
<h2 v-if="fastFilters['withTags'] == 1">Only showing notse with Tags</h2>
|
|
||||||
<h2 v-if="fastFilters['onlyArchived'] == 1">Only showing Archived notes.</h2>
|
|
||||||
|
|
||||||
<!-- Note title card display -->
|
<!-- Note title card display -->
|
||||||
<div class="sixteen wide column">
|
<div class="sixteen wide column">
|
||||||
<h3 v-if="searchTerm.length > 0 && notes.length == 0">No notes found. Check your spelling, try completing the word or using a different phrase.</h3>
|
<h3 v-if="searchTerm.length > 0 && notes.length == 0">No notes found. Check your spelling, try completing the word or using a different phrase.</h3>
|
||||||
|
|
||||||
<h3 v-if="searchTerm.length == 0 && notes.length == 0">Create your first note. Click the "New Note" button.</h3>
|
<h3 v-if="$store.getters.totals && $store.getters.totals['totalNotes'] == 0">
|
||||||
|
No Notes Yet. Create one when you feel ready.
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div v-if="working">
|
<!-- <div v-if="working">
|
||||||
<div class="ui active inline loader"></div> Working...
|
<div class="ui active inline loader"></div> Working...
|
||||||
</div>
|
</div> -->
|
||||||
|
|
||||||
<!-- Go to one wide column, do not do this on mobile interface -->
|
<!-- Go to one wide column, do not do this on mobile interface -->
|
||||||
<div v-if="notes !== null && notes.length > 0"
|
<div v-if="notes !== null && notes.length > 0"
|
||||||
@ -163,6 +161,7 @@
|
|||||||
'fast-filters': require('@/components/FastFilters.vue').default,
|
'fast-filters': require('@/components/FastFilters.vue').default,
|
||||||
'search-input': require('@/components/SearchInput.vue').default,
|
'search-input': require('@/components/SearchInput.vue').default,
|
||||||
'attachment-display': require('@/components/AttachmentDisplayCard').default,
|
'attachment-display': require('@/components/AttachmentDisplayCard').default,
|
||||||
|
'counter':require('@/components/AnimatedCounterComponent.vue').default
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
@ -204,7 +203,16 @@
|
|||||||
|
|
||||||
lastVisibilityState: null,
|
lastVisibilityState: null,
|
||||||
|
|
||||||
foundAttachments: []
|
foundAttachments: [],
|
||||||
|
|
||||||
|
noteSections: {
|
||||||
|
'pinned': {},
|
||||||
|
'archived': {},
|
||||||
|
'recieved': {},
|
||||||
|
'sent':{},
|
||||||
|
'notes':{},
|
||||||
|
'textMatch':{}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -654,7 +662,14 @@
|
|||||||
},
|
},
|
||||||
fetchUserTags(){
|
fetchUserTags(){
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
axios.post('/api/tag/usertags')
|
|
||||||
|
let postData = {
|
||||||
|
searchQuery: this.searchTerm,
|
||||||
|
searchTags: this.searchTags,
|
||||||
|
fastFilters: this.fastFilters,
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.post('/api/tag/usertags', postData)
|
||||||
.then( ({data}) => {
|
.then( ({data}) => {
|
||||||
this.commonTags = data
|
this.commonTags = data
|
||||||
resolve(data)
|
resolve(data)
|
||||||
|
@ -22,6 +22,18 @@ io.on('connection', function(socket){
|
|||||||
|
|
||||||
// console.log('New user ', socket.id)
|
// console.log('New user ', socket.id)
|
||||||
|
|
||||||
|
//When a user connects, add them to their own room
|
||||||
|
// This allows the server to emit events to that specific user
|
||||||
|
// access socket.io in the controller with req.io
|
||||||
|
socket.on('user_connect', token => {
|
||||||
|
Auth.decodeToken(token)
|
||||||
|
.then(userData => {
|
||||||
|
socket.join(userData.id)
|
||||||
|
}).catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
socket.on('join_room', roomId => {
|
socket.on('join_room', roomId => {
|
||||||
// console.log('Join room ', roomId)
|
// console.log('Join room ', roomId)
|
||||||
socket.join(roomId)
|
socket.join(roomId)
|
||||||
|
@ -226,7 +226,7 @@ Attachment.generateThumbnail = (fileName) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Scans text for websites, returns all attachments
|
//Scans text for websites, returns all attachments
|
||||||
Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
|
Attachment.scanTextForWebsites = (io, userId, noteId, noteText) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
let solrAttachmentText = '' //Final searchable scrape text for note
|
let solrAttachmentText = '' //Final searchable scrape text for note
|
||||||
@ -244,7 +244,7 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
|
|||||||
allUrls = []
|
allUrls = []
|
||||||
}
|
}
|
||||||
|
|
||||||
//Every URL needs HTTPS
|
//Every URL needs HTTPS!!!
|
||||||
let foundUrls = []
|
let foundUrls = []
|
||||||
allUrls.forEach( (item, index) => {
|
allUrls.forEach( (item, index) => {
|
||||||
//Every URL should have HTTPS
|
//Every URL should have HTTPS
|
||||||
@ -279,12 +279,17 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
|
|||||||
|
|
||||||
//No newly scraped URLs, resolve with looked up attachment text
|
//No newly scraped URLs, resolve with looked up attachment text
|
||||||
if(foundUrls == null || foundUrls.length == 0){
|
if(foundUrls == null || foundUrls.length == 0){
|
||||||
resolve(solrAttachmentText)
|
return resolve(solrAttachmentText)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Process the remaining URLs into attachments
|
//Process the remaining URLs into attachments
|
||||||
Attachment.scrapeUrlsCreateAttachments(userId, noteId, foundUrls).then( freshlyScrapedText => {
|
Attachment.scrapeUrlsCreateAttachments(userId, noteId, foundUrls).then( freshlyScrapedText => {
|
||||||
|
|
||||||
|
//Once everything is done being scraped, emit new attachment events
|
||||||
|
if(io){
|
||||||
|
io.to(userId).emit('update_counts')
|
||||||
|
}
|
||||||
|
|
||||||
solrAttachmentText += freshlyScrapedText
|
solrAttachmentText += freshlyScrapedText
|
||||||
resolve(solrAttachmentText)
|
resolve(solrAttachmentText)
|
||||||
})
|
})
|
||||||
|
@ -2,6 +2,7 @@ let db = require('@config/database')
|
|||||||
|
|
||||||
let Tags = require('@models/Tag')
|
let Tags = require('@models/Tag')
|
||||||
let Attachment = require('@models/Attachment')
|
let Attachment = require('@models/Attachment')
|
||||||
|
let ShareNote = require('@models/ShareNote')
|
||||||
|
|
||||||
let ProcessText = require('@helpers/ProcessText')
|
let ProcessText = require('@helpers/ProcessText')
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ Note.reindex = (userId, noteId) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
Note.update = (userId, noteId, noteText, color, pinned, archived) => {
|
Note.update = (io, userId, noteId, noteText, color, pinned, archived) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
//Prevent note loss if it saves with empty text
|
//Prevent note loss if it saves with empty text
|
||||||
@ -192,7 +193,7 @@ Note.update = (userId, noteId, noteText, color, pinned, archived) => {
|
|||||||
Note.reindex(userId, noteId)
|
Note.reindex(userId, noteId)
|
||||||
|
|
||||||
//Async attachment reindex
|
//Async attachment reindex
|
||||||
Attachment.scanTextForWebsites(userId, noteId, noteText)
|
Attachment.scanTextForWebsites(io, userId, noteId, noteText)
|
||||||
|
|
||||||
//Send back updated response
|
//Send back updated response
|
||||||
resolve(rows[0])
|
resolve(rows[0])
|
||||||
@ -258,6 +259,15 @@ Note.delete = (userId, noteId) => {
|
|||||||
.query('DELETE FROM note_tag WHERE note_tag.note_id = ? AND note_tag.user_id = ?', [noteId,userId])
|
.query('DELETE FROM note_tag WHERE note_tag.note_id = ? AND note_tag.user_id = ?', [noteId,userId])
|
||||||
})
|
})
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
|
//IF there are nots with a matching raw text id, we want to under their share status
|
||||||
|
db.promise().query('SELECT id FROM note WHERE note_raw_text_id = ?',[rawTextId])
|
||||||
|
.then((rows, fields) => {
|
||||||
|
if(rows[0].length == 1){
|
||||||
|
db.promise().query('UPDATE note SET shared = 0 WHERE id = ?', [rows[0][0]['id']])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
resolve(true)
|
resolve(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -325,8 +335,7 @@ Note.get = (userId, noteId) => {
|
|||||||
note.archived,
|
note.archived,
|
||||||
note.color,
|
note.color,
|
||||||
count(distinct attachment.id) as attachment_count,
|
count(distinct attachment.id) as attachment_count,
|
||||||
note.note_raw_text_id as rawTextId,
|
note.note_raw_text_id as rawTextId
|
||||||
user.username as shareUsername
|
|
||||||
FROM note
|
FROM note
|
||||||
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
||||||
LEFT JOIN attachment ON (note.id = attachment.note_id)
|
LEFT JOIN attachment ON (note.id = attachment.note_id)
|
||||||
@ -450,7 +459,8 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
|
|||||||
note.archived,
|
note.archived,
|
||||||
GROUP_CONCAT(DISTINCT tag.text) as tags,
|
GROUP_CONCAT(DISTINCT tag.text) as tags,
|
||||||
GROUP_CONCAT(DISTINCT attachment.file_location) as thumbs,
|
GROUP_CONCAT(DISTINCT attachment.file_location) as thumbs,
|
||||||
shareUser.username as username
|
shareUser.username as shareUsername,
|
||||||
|
note.shared
|
||||||
FROM note
|
FROM note
|
||||||
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
|
||||||
LEFT JOIN note_tag ON (note.id = note_tag.note_id)
|
LEFT JOIN note_tag ON (note.id = note_tag.note_id)
|
||||||
@ -462,7 +472,10 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
|
|||||||
|
|
||||||
//Show shared notes
|
//Show shared notes
|
||||||
if(fastFilters.onlyShowSharedNotes == 1){
|
if(fastFilters.onlyShowSharedNotes == 1){
|
||||||
noteSearchQuery += ' AND note.share_user_id IS NOT NULL' //Show Archived
|
//share_user_id means your shared them, a note with a shared user id filled in means it was shared
|
||||||
|
noteSearchQuery += ` AND share_user_id IS NOT NULL OR (note.shared = 2 AND note.user_id = ?)`
|
||||||
|
searchParams.push(userId)
|
||||||
|
//Show notes shared with you
|
||||||
} else {
|
} else {
|
||||||
noteSearchQuery += ' AND note.share_user_id IS NULL'
|
noteSearchQuery += ' AND note.share_user_id IS NULL'
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ QuickNote.update = (userId, pushText) => {
|
|||||||
let newText = broken +''+ d.text
|
let newText = broken +''+ d.text
|
||||||
|
|
||||||
//Save that, then return the new text
|
//Save that, then return the new text
|
||||||
Note.update(userId, d.id, newText, d.color, d.pinned, d.archived)
|
Note.update(null, userId, d.id, newText, d.color, d.pinned, d.archived)
|
||||||
.then( saveResults => {
|
.then( saveResults => {
|
||||||
resolve({
|
resolve({
|
||||||
id:d.id,
|
id:d.id,
|
||||||
|
@ -15,9 +15,10 @@ ShareNote.addUser = (userId, noteId, rawTextId, username) => {
|
|||||||
|
|
||||||
let shareUserId = null
|
let shareUserId = null
|
||||||
let newNoteShare = null
|
let newNoteShare = null
|
||||||
|
const cleanUser = username.toLowerCase().trim()
|
||||||
|
|
||||||
//Check that user actually exists
|
//Check that user actually exists
|
||||||
db.promise().query(`SELECT id FROM user WHERE username = ?`, [username])
|
db.promise().query(`SELECT id FROM user WHERE LOWER(username) = ?`, [cleanUser])
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
if(rows[0].length == 0){
|
if(rows[0].length == 0){
|
||||||
@ -69,11 +70,17 @@ ShareNote.addUser = (userId, noteId, rawTextId, username) => {
|
|||||||
})
|
})
|
||||||
.then((rows, fields) => {
|
.then((rows, fields) => {
|
||||||
|
|
||||||
|
//Update note share status to 2
|
||||||
|
return db.promise()
|
||||||
|
.query('UPDATE note SET shared = 2 WHERE id = ?', [noteId])
|
||||||
|
|
||||||
|
})
|
||||||
|
.then((rows, fields) => {
|
||||||
//Success!
|
//Success!
|
||||||
return resolve(true)
|
return resolve({'success':true, shareUserId})
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
// console.log(error)
|
console.log(error)
|
||||||
resolve(false)
|
resolve(false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -102,25 +109,38 @@ ShareNote.getUsers = (userId, rawTextId) => {
|
|||||||
// Remove a user from a shared note
|
// Remove a user from a shared note
|
||||||
ShareNote.removeUser = (userId, noteId) => {
|
ShareNote.removeUser = (userId, noteId) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const Note = require('@models/Note')
|
||||||
|
|
||||||
|
let rawTextId = null
|
||||||
|
let removeUserId = null
|
||||||
|
|
||||||
//note.id = noteId, share_user_id = userId
|
//note.id = noteId, share_user_id = userId
|
||||||
db.promise()
|
db.promise()
|
||||||
.query('SELECT user_id FROM note WHERE id = ? AND share_user_id = ?', [noteId, userId])
|
.query('SELECT note_raw_text_id, user_id FROM note WHERE id = ? AND share_user_id = ?', [noteId, userId])
|
||||||
.then( (rows, fields) => {
|
.then( (rows, fields) => {
|
||||||
|
|
||||||
//User has shared this note, with this user
|
rawTextId = rows[0][0]['note_raw_text_id']
|
||||||
if(rows[0].length == 1 && Number.isInteger(rows[0][0]['user_id'])){
|
removeUserId = rows[0][0]['user_id']
|
||||||
|
|
||||||
Note.delete(rows[0][0]['user_id'], noteId)
|
//Delete note entry for other user - remove users access
|
||||||
.then( result => {
|
if(removeUserId && Number.isInteger(removeUserId)){
|
||||||
resolve(result)
|
//Delete this users access to the note
|
||||||
})
|
return Note.delete(removeUserId, noteId)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return resolve(false)
|
|
||||||
|
return new Promise((resolve, reject) => { resolve(true) })
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
.then(stuff => {
|
||||||
|
resolve(true)
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error)
|
||||||
|
resolve(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -2,16 +2,40 @@ let db = require('@config/database')
|
|||||||
|
|
||||||
let Tag = module.exports = {}
|
let Tag = module.exports = {}
|
||||||
|
|
||||||
Tag.userTags = (userId) => {
|
Tag.userTags = (userId, searchQuery, searchTags, fastFilters) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.promise()
|
|
||||||
.query(`
|
let query = `
|
||||||
SELECT tag.id, text, COUNT(note_tag.note_id) as usages FROM tag
|
SELECT
|
||||||
|
tag.id,
|
||||||
|
text,
|
||||||
|
COUNT(note_tag.note_id) as usages
|
||||||
|
FROM tag
|
||||||
JOIN note_tag ON tag.id = note_tag.tag_id
|
JOIN note_tag ON tag.id = note_tag.tag_id
|
||||||
|
JOIN note On note.id = note_tag.note_id
|
||||||
WHERE note_tag.user_id = ?
|
WHERE note_tag.user_id = ?
|
||||||
GROUP BY tag.id
|
`
|
||||||
ORDER BY id DESC
|
|
||||||
`, [userId])
|
//Show shared notes
|
||||||
|
if(fastFilters && fastFilters.onlyShowSharedNotes == 1){
|
||||||
|
query += ' AND note.share_user_id IS NOT NULL' //Show Archived
|
||||||
|
} else {
|
||||||
|
query += ' AND note.share_user_id IS NULL'
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show archived notes, only if fast filter is set, default to not archived
|
||||||
|
if(fastFilters && fastFilters.onlyArchived == 1){
|
||||||
|
query += ' AND note.archived = 1' //Show Archived
|
||||||
|
} else {
|
||||||
|
query += ' AND note.archived = 0' //Exclude archived
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ` GROUP BY tag.id
|
||||||
|
ORDER BY usages DESC, text ASC`
|
||||||
|
|
||||||
|
|
||||||
|
db.promise()
|
||||||
|
.query(query, [userId])
|
||||||
.then( (rows, fields) => {
|
.then( (rows, fields) => {
|
||||||
resolve(rows[0])
|
resolve(rows[0])
|
||||||
})
|
})
|
||||||
|
@ -123,7 +123,7 @@ User.getCounts = (userId) => {
|
|||||||
db.promise().query(
|
db.promise().query(
|
||||||
`SELECT
|
`SELECT
|
||||||
SUM(pinned = 1 && archived = 0 && share_user_id IS NULL) AS pinnedNotes,
|
SUM(pinned = 1 && archived = 0 && share_user_id IS NULL) AS pinnedNotes,
|
||||||
SUM(pinned = 0 && archived = 1 && share_user_id IS NULL) AS archivedNotes,
|
SUM(archived = 1 && share_user_id IS NULL) AS archivedNotes,
|
||||||
SUM(share_user_id IS NULL) AS totalNotes,
|
SUM(share_user_id IS NULL) AS totalNotes,
|
||||||
SUM(share_user_id != ?) AS sharedToNotes,
|
SUM(share_user_id != ?) AS sharedToNotes,
|
||||||
SUM( (share_user_id != ? && opened IS null) || (share_user_id != ? && updated > opened) ) AS unreadNotes
|
SUM( (share_user_id != ? && opened IS null) || (share_user_id != ? && updated > opened) ) AS unreadNotes
|
||||||
|
@ -54,7 +54,7 @@ router.post('/upload', upload.single('file'), function (req, res, next) {
|
|||||||
.then( uploadResults => {
|
.then( uploadResults => {
|
||||||
//Reindex note, attachment may have had text
|
//Reindex note, attachment may have had text
|
||||||
Note.reindex(userId, noteId)
|
Note.reindex(userId, noteId)
|
||||||
.then( data => res.send(uploadResults) )
|
.then( data => {res.send(uploadResults)})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -23,7 +23,7 @@ router.use(function setUserId (req, res, next) {
|
|||||||
// Note actions
|
// Note actions
|
||||||
//
|
//
|
||||||
router.post('/get', function (req, res) {
|
router.post('/get', function (req, res) {
|
||||||
req.io.emit('welcome_homie', 'Welcome, dont poop from excitement')
|
// req.io.emit('welcome_homie', 'Welcome, dont poop from excitement')
|
||||||
Notes.get(userId, req.body.noteId)
|
Notes.get(userId, req.body.noteId)
|
||||||
.then( data => {
|
.then( data => {
|
||||||
//Join room when user opens note
|
//Join room when user opens note
|
||||||
@ -43,7 +43,7 @@ router.post('/create', function (req, res) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
router.post('/update', function (req, res) {
|
router.post('/update', function (req, res) {
|
||||||
Notes.update(userId, req.body.noteId, req.body.text, req.body.color, req.body.pinned, req.body.archived)
|
Notes.update(req.io, userId, req.body.noteId, req.body.text, req.body.color, req.body.pinned, req.body.archived)
|
||||||
.then( id => res.send({id}) )
|
.then( id => res.send({id}) )
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -72,7 +72,13 @@ router.post('/getshareusers', function (req, res) {
|
|||||||
|
|
||||||
router.post('/shareadduser', function (req, res) {
|
router.post('/shareadduser', function (req, res) {
|
||||||
ShareNote.addUser(userId, req.body.noteId, req.body.rawTextId, req.body.username)
|
ShareNote.addUser(userId, req.body.noteId, req.body.rawTextId, req.body.username)
|
||||||
.then(results => res.send(results))
|
.then( ({success, shareUserId}) => {
|
||||||
|
|
||||||
|
//Emit update count event to user shared with - so they see the note in real time
|
||||||
|
req.io.to(shareUserId).emit('update_counts')
|
||||||
|
|
||||||
|
res.send(success)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/shareremoveuser', function (req, res) {
|
router.post('/shareremoveuser', function (req, res) {
|
||||||
|
@ -44,7 +44,7 @@ router.post('/get', function (req, res) {
|
|||||||
|
|
||||||
//Get all the tags for this user in order of usage
|
//Get all the tags for this user in order of usage
|
||||||
router.post('/usertags', function (req, res) {
|
router.post('/usertags', function (req, res) {
|
||||||
Tags.userTags(userId)
|
Tags.userTags(userId, req.body.searchQuery, req.body.searchTags, req.body.fastFilters)
|
||||||
.then( data => res.send(data) )
|
.then( data => res.send(data) )
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user