Added some realtime events to the app
* When a user gets a new shared message, it will popup instantly * When a new website is scraped, it will update in real time * Various other little bug fixes and improvements * Sharing displays correct notes and handles shared notes correctly * Tags were not displaying on notes, they do now. They better.
This commit is contained in:
		@@ -27,10 +27,17 @@ export default {
 | 
			
		||||
	},
 | 
			
		||||
	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 = this.$io
 | 
			
		||||
		socket.on('connect', () => {
 | 
			
		||||
 | 
			
		||||
			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
 | 
			
		||||
@@ -41,16 +48,20 @@ export default {
 | 
			
		||||
			this.$store.commit('toggleNightMode')
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		//Puts token into state on page load
 | 
			
		||||
		let token = localStorage.getItem('loginToken')
 | 
			
		||||
		let username = localStorage.getItem('username')
 | 
			
		||||
 | 
			
		||||
		//Put user data into global store on load
 | 
			
		||||
		if(token){
 | 
			
		||||
			this.$store.commit('setLoginToken', {token, username})
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	},
 | 
			
		||||
	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: {
 | 
			
		||||
		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 {
 | 
			
		||||
			color: #fff;
 | 
			
		||||
			padding: 0.8em 0px 0.8em 10px;
 | 
			
		||||
			padding: 0.8em 10px 0.8em 10px;
 | 
			
		||||
			display: inline-block;
 | 
			
		||||
			width: 100%;
 | 
			
		||||
			font-size: 1.15em;
 | 
			
		||||
@@ -154,7 +154,7 @@
 | 
			
		||||
			<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()">
 | 
			
		||||
					<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>
 | 
			
		||||
				<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']">
 | 
			
		||||
				<router-link class="menu-item menu-button" exact-active-class="active" to="/attachments">
 | 
			
		||||
					<i class="folder open outline icon"></i>Files
 | 
			
		||||
					<!-- <span>{{ $store.getters.totals['totalFiles'] }}</span> -->
 | 
			
		||||
					<counter class="float-right" number-id="totalFiles" />
 | 
			
		||||
				</router-link>
 | 
			
		||||
			</div>
 | 
			
		||||
 | 
			
		||||
@@ -216,6 +216,7 @@
 | 
			
		||||
	export default {
 | 
			
		||||
		components: {
 | 
			
		||||
			'search-input': require('@/components/SearchInput.vue').default,
 | 
			
		||||
			'counter':require('@/components/AnimatedCounterComponent.vue').default,
 | 
			
		||||
		},
 | 
			
		||||
		data: function(){ 
 | 
			
		||||
			return {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,10 @@
 | 
			
		||||
 | 
			
		||||
				<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  -->
 | 
			
		||||
					<div v-if="note.title.length > 0" 
 | 
			
		||||
						data-test-id="title"
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,11 @@
 | 
			
		||||
					
 | 
			
		||||
					<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;">
 | 
			
		||||
							<i class="green mail icon"></i>Inbox
 | 
			
		||||
						<div class="ui basic button" 
 | 
			
		||||
						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">
 | 
			
		||||
								{{ $store.getters.totals['unreadNotes'] }}
 | 
			
		||||
							</span>
 | 
			
		||||
@@ -40,6 +43,11 @@
 | 
			
		||||
 | 
			
		||||
			</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="commonTags.length > 0" class="sixteen wide column">
 | 
			
		||||
				<h4><i class="green tags icon"></i>Tags</h4>
 | 
			
		||||
@@ -50,19 +58,17 @@
 | 
			
		||||
				</span>
 | 
			
		||||
			</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  -->
 | 
			
		||||
			<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">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>
 | 
			
		||||
				</div> -->
 | 
			
		||||
 | 
			
		||||
				<!-- Go to one wide column, do not do this on mobile interface -->
 | 
			
		||||
				<div v-if="notes !== null && notes.length > 0" 
 | 
			
		||||
@@ -155,6 +161,7 @@
 | 
			
		||||
			'fast-filters': require('@/components/FastFilters.vue').default,
 | 
			
		||||
			'search-input': require('@/components/SearchInput.vue').default,
 | 
			
		||||
			'attachment-display': require('@/components/AttachmentDisplayCard').default,
 | 
			
		||||
			'counter':require('@/components/AnimatedCounterComponent.vue').default
 | 
			
		||||
		},
 | 
			
		||||
		data () {
 | 
			
		||||
			return {
 | 
			
		||||
@@ -196,7 +203,16 @@
 | 
			
		||||
 | 
			
		||||
				lastVisibilityState: null,
 | 
			
		||||
 | 
			
		||||
				foundAttachments: []
 | 
			
		||||
				foundAttachments: [],
 | 
			
		||||
 | 
			
		||||
				noteSections: {
 | 
			
		||||
					'pinned': {},
 | 
			
		||||
					'archived': {},
 | 
			
		||||
					'recieved': {},
 | 
			
		||||
					'sent':{},
 | 
			
		||||
					'notes':{},
 | 
			
		||||
					'textMatch':{}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,18 @@ io.on('connection', function(socket){
 | 
			
		||||
 | 
			
		||||
	// 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 => {
 | 
			
		||||
		// console.log('Join room ', roomId)
 | 
			
		||||
		socket.join(roomId)
 | 
			
		||||
 
 | 
			
		||||
@@ -226,7 +226,7 @@ Attachment.generateThumbnail = (fileName) => {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//Scans text for websites, returns all attachments
 | 
			
		||||
Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
 | 
			
		||||
Attachment.scanTextForWebsites = (io, userId, noteId, noteText) => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
 | 
			
		||||
		let solrAttachmentText = '' //Final searchable scrape text for note
 | 
			
		||||
@@ -244,7 +244,7 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
 | 
			
		||||
				allUrls = []
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Every URL needs HTTPS
 | 
			
		||||
			//Every URL needs HTTPS!!!
 | 
			
		||||
			let foundUrls = []
 | 
			
		||||
			allUrls.forEach( (item, index) => {
 | 
			
		||||
				//Every URL should have HTTPS
 | 
			
		||||
@@ -279,12 +279,17 @@ Attachment.scanTextForWebsites = (userId, noteId, noteText) => {
 | 
			
		||||
 | 
			
		||||
			//No newly scraped URLs, resolve with looked up attachment text
 | 
			
		||||
			if(foundUrls == null || foundUrls.length == 0){
 | 
			
		||||
				resolve(solrAttachmentText)
 | 
			
		||||
				return resolve(solrAttachmentText)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			//Process the remaining URLs into attachments
 | 
			
		||||
			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
 | 
			
		||||
				resolve(solrAttachmentText)
 | 
			
		||||
			})
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ let db = require('@config/database')
 | 
			
		||||
 | 
			
		||||
let Tags = require('@models/Tag')
 | 
			
		||||
let Attachment = require('@models/Attachment')
 | 
			
		||||
let ShareNote = require('@models/ShareNote')
 | 
			
		||||
 | 
			
		||||
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) => {
 | 
			
		||||
 | 
			
		||||
		//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)
 | 
			
		||||
 | 
			
		||||
			//Async attachment reindex
 | 
			
		||||
			Attachment.scanTextForWebsites(userId, noteId, noteText)
 | 
			
		||||
			Attachment.scanTextForWebsites(io, userId, noteId, noteText)
 | 
			
		||||
			
 | 
			
		||||
			//Send back updated response
 | 
			
		||||
			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])	
 | 
			
		||||
		})
 | 
			
		||||
		.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)
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
@@ -325,8 +335,7 @@ Note.get = (userId, noteId) => {
 | 
			
		||||
				note.archived,
 | 
			
		||||
				note.color,
 | 
			
		||||
				count(distinct attachment.id) as attachment_count,
 | 
			
		||||
				note.note_raw_text_id as rawTextId,
 | 
			
		||||
				user.username as shareUsername
 | 
			
		||||
				note.note_raw_text_id as rawTextId
 | 
			
		||||
			FROM note 
 | 
			
		||||
			JOIN note_raw_text ON (note_raw_text.id = note.note_raw_text_id)
 | 
			
		||||
			LEFT JOIN attachment ON (note.id = attachment.note_id)
 | 
			
		||||
@@ -450,7 +459,8 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
 | 
			
		||||
					note.archived,
 | 
			
		||||
					GROUP_CONCAT(DISTINCT tag.text) as tags,
 | 
			
		||||
					GROUP_CONCAT(DISTINCT attachment.file_location) as thumbs,
 | 
			
		||||
					shareUser.username as username
 | 
			
		||||
					shareUser.username as shareUsername,
 | 
			
		||||
					note.shared
 | 
			
		||||
				FROM note 
 | 
			
		||||
				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)
 | 
			
		||||
@@ -462,7 +472,10 @@ Note.search = (userId, searchQuery, searchTags, fastFilters) => {
 | 
			
		||||
			
 | 
			
		||||
			//Show shared notes
 | 
			
		||||
			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 {
 | 
			
		||||
				noteSearchQuery += ' AND note.share_user_id IS NULL'
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ QuickNote.update = (userId, pushText) => {
 | 
			
		||||
				let newText = broken +''+ d.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 => {
 | 
			
		||||
					resolve({
 | 
			
		||||
						id:d.id,
 | 
			
		||||
 
 | 
			
		||||
@@ -15,9 +15,10 @@ ShareNote.addUser = (userId, noteId, rawTextId, username) => {
 | 
			
		||||
 | 
			
		||||
		let shareUserId = null
 | 
			
		||||
		let newNoteShare = null
 | 
			
		||||
		const cleanUser = username.toLowerCase().trim()
 | 
			
		||||
 | 
			
		||||
		//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) => {
 | 
			
		||||
 | 
			
		||||
			if(rows[0].length == 0){
 | 
			
		||||
@@ -69,11 +70,17 @@ ShareNote.addUser = (userId, noteId, rawTextId, username) => {
 | 
			
		||||
		})
 | 
			
		||||
		.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!
 | 
			
		||||
			return resolve(true)
 | 
			
		||||
			return resolve({'success':true, shareUserId})
 | 
			
		||||
		})
 | 
			
		||||
		.catch(error => {
 | 
			
		||||
			// console.log(error)
 | 
			
		||||
			console.log(error)
 | 
			
		||||
			resolve(false)
 | 
			
		||||
		})
 | 
			
		||||
	})
 | 
			
		||||
@@ -102,25 +109,38 @@ ShareNote.getUsers = (userId, rawTextId) => {
 | 
			
		||||
// Remove a user from a shared note
 | 
			
		||||
ShareNote.removeUser = (userId, noteId) => {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
 | 
			
		||||
		const Note = require('@models/Note')
 | 
			
		||||
 | 
			
		||||
		let rawTextId = null
 | 
			
		||||
		let removeUserId = null
 | 
			
		||||
		
 | 
			
		||||
		//note.id = noteId, share_user_id = userId
 | 
			
		||||
		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) => {
 | 
			
		||||
 | 
			
		||||
			//User has shared this note, with this user
 | 
			
		||||
			if(rows[0].length == 1 && Number.isInteger(rows[0][0]['user_id'])){
 | 
			
		||||
			rawTextId = rows[0][0]['note_raw_text_id']
 | 
			
		||||
			removeUserId = rows[0][0]['user_id']
 | 
			
		||||
 | 
			
		||||
				Note.delete(rows[0][0]['user_id'], noteId)
 | 
			
		||||
				.then( result => {
 | 
			
		||||
					resolve(result)
 | 
			
		||||
				})
 | 
			
		||||
			//Delete note entry for other user - remove users access
 | 
			
		||||
			if(removeUserId && Number.isInteger(removeUserId)){
 | 
			
		||||
				//Delete this users access to the note
 | 
			
		||||
				return Note.delete(removeUserId, noteId)
 | 
			
		||||
 | 
			
		||||
			} else {
 | 
			
		||||
				return resolve(false)
 | 
			
		||||
				
 | 
			
		||||
				return new Promise((resolve, reject) => { resolve(true) })
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		})
 | 
			
		||||
		.then(stuff => {
 | 
			
		||||
			resolve(true)
 | 
			
		||||
		})
 | 
			
		||||
		.catch(error => {
 | 
			
		||||
			console.log(error)
 | 
			
		||||
			resolve(false)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	})
 | 
			
		||||
 
 | 
			
		||||
@@ -17,21 +17,21 @@ Tag.userTags = (userId, searchQuery, searchTags, fastFilters) => {
 | 
			
		||||
		`
 | 
			
		||||
 | 
			
		||||
		//Show shared notes
 | 
			
		||||
		if(fastFilters.onlyShowSharedNotes == 1){
 | 
			
		||||
		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.onlyArchived == 1){
 | 
			
		||||
		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 id DESC`
 | 
			
		||||
			ORDER BY usages DESC, text ASC`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		db.promise()
 | 
			
		||||
 
 | 
			
		||||
@@ -123,7 +123,7 @@ User.getCounts = (userId) => {
 | 
			
		||||
		db.promise().query(
 | 
			
		||||
			`SELECT
 | 
			
		||||
				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 != ?) AS sharedToNotes,
 | 
			
		||||
				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 => {
 | 
			
		||||
		//Reindex note, attachment may have had text
 | 
			
		||||
		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
 | 
			
		||||
//
 | 
			
		||||
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)
 | 
			
		||||
	.then( data => {
 | 
			
		||||
		//Join room when user opens note
 | 
			
		||||
@@ -43,7 +43,7 @@ router.post('/create', 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}) )
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +72,13 @@ router.post('/getshareusers', function (req, res) {
 | 
			
		||||
 | 
			
		||||
router.post('/shareadduser', function (req, res) {
 | 
			
		||||
	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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user