Not really sure what is going on, have not done a commit in a while.

I assume this is all the metric tracking changes.
Looks like some script changes as well.
This commit is contained in:
Max 2023-02-12 18:41:55 +00:00
parent 48c1fa8e69
commit 39e153b8e1
15 changed files with 303 additions and 1480 deletions

View File

@ -1,12 +1,15 @@
#!/bin/bash #!/bin/bash
# Take all variables in .env and turn them into local variables for this script
source ~/.env
BACKUPDIR="/home/mab/databaseBackupSolidScribe" BACKUPDIR="/home/mab/databaseBackupSolidScribe"
mkdir -p $BACKUPDIR mkdir -p $BACKUPDIR
cd $BACKUPDIR cd $BACKUPDIR
NOW=$(date +"%Y-%m-%d_%H-%M") NOW=$(date +"%Y-%m-%d_%H-%M")
ssh mab@solidscribe.com -p 13328 "mysqldump --all-databases --single-transaction --user root -p***REMOVED***" > "backup-$NOW.sql" ssh mab@solidscribe.com -p 13328 "mysqldump --all-databases --single-transaction --user root -p$PROD_DB_PASS" > "backup-$NOW.sql"
gzip "backup-$NOW.sql" gzip "backup-$NOW.sql"
# cp "backup-$NOW.sql" "/mnt/Windows Data/DatabaseBackups/backup-$NOW.sql" # cp "backup-$NOW.sql" "/mnt/Windows Data/DatabaseBackups/backup-$NOW.sql"

View File

@ -146,6 +146,9 @@ body {
.ui.dividing.header { .ui.dividing.header {
border-bottom-color: var(--dark_border_color); border-bottom-color: var(--dark_border_color);
} }
.ui.dividing.header > .sub.header {
color: var(--dark_border_color);
}
.ui.icon.input > i.icon { .ui.icon.input > i.icon {
color: var(--text_color); color: var(--text_color);
} }
@ -180,10 +183,15 @@ i.green.icon.icon.icon.icon, i.green.icon.icon.icon.icon.icon {
.button { .button {
box-shadow: 2px 2px 4px -2px rgba(40, 40, 40, 0.89) !important; box-shadow: 2px 2px 4px -2px rgba(40, 40, 40, 0.89) !important;
transition: all 0.9s ease; transition: all 0.9s ease;
position: relative;
} }
.button:hover { .button:hover {
box-shadow: 3px 2px 5px -2px rgba(40, 40, 40, 0.95) !important; box-shadow: 3px 2px 3px -2px rgba(40, 40, 40, 0.95) !important;
} }
.button:active {
transform: translateY(1px);
}
.ui.green.buttons, .ui.green.button, .ui.green.button:hover { .ui.green.buttons, .ui.green.button, .ui.green.button:hover {
background-color: var(--main-accent); background-color: var(--main-accent);
} }

View File

@ -15,7 +15,7 @@
box-sizing: border-box; box-sizing: border-box;
display: block; display: block;
position: fixed; position: fixed;
z-index: 111; z-index: 900;
top: 0; top: 0;
left: 0; left: 0;
bottom: 0; bottom: 0;
@ -66,7 +66,7 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
background-color: rgba(0,0,0,0.7); background-color: rgba(0,0,0,0.7);
z-index: 100; z-index: 899;
cursor: pointer; cursor: pointer;
} }
.top-menu-bar { .top-menu-bar {
@ -526,8 +526,11 @@
location.reload(true) location.reload(true)
}, },
getVersionIcon(){ getVersionIcon(){
if(!this.version){
return 'radiation alternate'
}
const icons = ['cat','crow','dog','dove','dragon','fish','frog','hippo','horse','kiwi bird','otter','spider', 'smile', 'robot', 'hat wizard', 'microchip', 'atom', 'grin tongue squint', 'radiation', 'ghost', 'dna', 'burn', 'brain', 'moon', 'torii gate'] const icons = ['cat','crow','dog','dove','dragon','fish','frog','hippo','horse','kiwi bird','otter','spider', 'smile', 'robot', 'hat wizard', 'microchip', 'atom', 'grin tongue squint', 'radiation', 'ghost', 'dna', 'burn', 'brain', 'moon', 'torii gate']
const index = ( parseInt(this.version.replace(/\./g,'')) % (icons.length)) const index = ( parseInt(String(this.version).replace(/\./g,'')) % (icons.length))
return icons[index] return icons[index]
} }

View File

@ -0,0 +1,164 @@
<style type="text/css" scoped>
.modal-content {
position: fixed;
top: 40%;
left: 50%;
/* bring your own prefixes */
transform: translate(-50%, -40%);
z-index: 300;
padding: 1em;
box-sizing: border-box;
width: 50%;
max-height: 100%;
/*overflow: hidden;*/
overflow-y: scroll;
font-weight: normal;
}
.modal-content.fullscreen {
width: 96%;
height: 100%;
max-height: 100%;
}
.close-container {
position: fixed;
top: 5px;
right: 5px;
z-index: 320;
}
/* Shrink button text for mobile */
@media only screen and (max-width: 740px) {
.modal-content {
width: 100%;
padding-bottom: 55px;
}
}
.modal-content.right-side {
width: 60%;
max-height: none;
height: 100vh;
padding: 0;
margin: 0;
top: 0;
bottom: 0;
left: 0;
left: auto;
transform: translate(0, 0);
}
.close-container-right-side {
position: fixed;
top: 5px;
left: calc(60% + 2px);
z-index: 320;
}
.shade {
position: fixed;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #0000007d;
z-index: 299;
backdrop-filter: blur(2px);
}
.fade-out-top {
animation: fade-out-top 0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.fade-out {
animation: fade-out 0.3s ease-out both;
}
@keyframes fade-out-top {
0% {
/*transform: translate(-50%, -50%);*/
opacity: 1;
}
100% {
/*transform: translate(-50%, -70%);*/
opacity: 0;
}
}
@keyframes fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fade-in {
/*animation: fade-in 0.3s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;*/
}
@keyframes fade-in {
0% {
transform: translate(-50%, -70%);
opacity: 0;
}
100% {
transform: translate(-50%, -50%);
opacity: 1;
}
}
</style>
<template>
<div v-if="openModel">
<div class="modal-content" :class="{ 'fade-out-top':(animateOut), 'fade-in':(!animateOut), 'fullscreen':(fullscreen)}">
<slot></slot>
</div>
<!-- full screen close button -->
<div class="close-container" v-if="fullscreen && clickOutClose !== false">
<div class="ui green icon button" v-on:click="closeModel">
<i class="close icon"></i>
</div>
</div>
<div class="shade" v-on:click="closeModel" v-on:mouseenter=" hoverOutClose?closeModel():null " :class="{ 'fade-out':(animateOut) }"></div>
</div>
</template>
<script>
export default {
props: [
'fullscreen', //Make the model really big
'clickOutClose', //Set to false to prevent closing of modal by clicking out
'hoverOutClose', //Close if cursor leaves modal
],
data: function(){
return {
openModel:true,
animateOut:false,
}
},
methods: {
closeModel(){
//Don't allow closing by clicking out
if(this.clickOutClose === false){
return
}
//Set stups to close model, animate out
this.animateOut = true
setTimeout( () => {
this.openModel = false
this.$emit('close')
//Once close event is sent, reset to default state
this.animateOut = false
this.openModel = true
}, 800)
},
}
}
</script>

View File

@ -35,7 +35,6 @@
<i class="search icon"></i> <i class="search icon"></i>
</div> </div>
<div class="floating-button" v-if="searchTerm.length > 0"> <div class="floating-button" v-if="searchTerm.length > 0">
<i class="big link grey close icon" v-on:click="clear()"></i> <i class="big link grey close icon" v-on:click="clear()"></i>
</div> </div>

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,12 @@
animation: fadeorama 16s ease infinite; animation: fadeorama 16s ease infinite;
height: 350px; height: 350px;
text-shadow: 1px 1px 2px black; text-shadow:
1px 1px 1px rgba(69,69,69,0.1),
-1px -1px 1px rgba(69,69,69,0.1),
-1px 1px 1px rgba(69,69,69,0.1),
1px -1px 1px rgba(69,69,69,0.1)
;
} }
.shine { .shine {
position: absolute; position: absolute;
@ -492,6 +497,8 @@
<a target="_blank" href="https://www.maxg.cc">Solid Scribe was created by Max Gialanella</a> <a target="_blank" href="https://www.maxg.cc">Solid Scribe was created by Max Gialanella</a>
</h3> </h3>
<p><a target="_blank" href="https://www.maxg.cc">Check out my Resume</a></p> <p><a target="_blank" href="https://www.maxg.cc">Check out my Resume</a></p>
<p>OR</p>
<p><a target="_blank" href="http://blog.maxg.cc">Check out my Programming Blog</a></p>
<p> <p>
I was tired of all my data being owned by big companies, having it farmed out for marketing, and leaving the contents of my life exposed to corporations. I was tired of all my data being owned by big companies, having it farmed out for marketing, and leaving the contents of my life exposed to corporations.
</p> </p>

View File

@ -12,6 +12,12 @@
<search-input /> <search-input />
</div> </div>
<div class="sixteen wide column" v-if="$store.getters.totals && $store.getters.totals['showTrackMetricsButton']">
<router-link class="ui fluid green button" to="/metrictrack">
<i class="calendar check outlin icon"></i>Metric Track
</router-link>
</div>
<div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }"> <div class="ten wide column" :class="{ 'sixteen wide column':$store.getters.getIsUserOnMobile }">
<div class="ui basic button shrinking" <div class="ui basic button shrinking"
@ -110,7 +116,7 @@
</div> </div>
<div class="ui small green button" v-on:click="collapseFloatingList = true"> <div class="ui small green button" v-on:click="collapseFloatingList = true">
<i class="caret square left outline icon"></i> <i class="caret square left outline icon"></i>
Hide Menu Hide List
</div> </div>
</div> </div>
@ -154,7 +160,8 @@
</div> </div>
<div class="show-hidden-note-list-button" v-if="collapseFloatingList" v-on:click="collapseFloatingList = false"> <div class="show-hidden-note-list-button"
v-if="collapseFloatingList && openNotes.length > 0" v-on:click="collapseFloatingList = false">
<i class="caret square right outline icon"></i> <i class="caret square right outline icon"></i>
</div> </div>

View File

@ -120,7 +120,7 @@ export default new Router({
path: '/metrictrack', path: '/metrictrack',
name: 'Metric Tracking', name: 'Metric Tracking',
meta: {title:'Metric Tracking'}, meta: {title:'Metric Tracking'},
component: () => import(/* webpackChunkName: "CycletrackingPage" */ '@/pages/CycletrackingPage') component: () => import(/* webpackChunkName: "MetrictrackingPage" */ '@/pages/MetrictrackingPage')
}, },
] ]
}) })

View File

@ -10,7 +10,7 @@ export default new Vuex.Store({
nightMode: false, nightMode: false,
isUserOnMobile: false, isUserOnMobile: false,
fetchTotalsTimeout: null, fetchTotalsTimeout: null,
userTotals: null, userTotals: null, // {} // setting this to object breaks reactivity
activeSessions: 0, activeSessions: 0,
}, },
mutations: { mutations: {
@ -101,8 +101,23 @@ export default new Vuex.Store({
state.socket = socket state.socket = socket
}, },
setUserTotals(state, totalsObject){ setUserTotals(state, totalsObject){
//Save all the totals for the user
state.userTotals = totalsObject if(!state.userTotals){
state.userTotals = {}
}
// retain old values loaded on initial, extended options load
let oldMissingValues = {}
Object.keys(state.userTotals).forEach(key => {
if(!totalsObject[key] && totalsObject[key] !== 0){
oldMissingValues[key] = state.userTotals[key]
}
})
// combine old settings with updated settings
let oldAndNew = Object.assign(oldMissingValues, totalsObject)
state.userTotals = oldAndNew
//Set computer version from server //Set computer version from server
const currentVersion = localStorage.getItem('currentVersion') const currentVersion = localStorage.getItem('currentVersion')
@ -126,6 +141,11 @@ export default new Vuex.Store({
setActiveSessions(state, countData){ setActiveSessions(state, countData){
//Count of the number of active socket.io sessions for this user //Count of the number of active socket.io sessions for this user
state.activeSessions = countData state.activeSessions = countData
},
hideMetricTrackingReminder(state){
if(state.userTotals){
state.userTotals['showTrackMetricsButton'] = false
}
} }
}, },
getters: { getters: {
@ -159,7 +179,11 @@ export default new Vuex.Store({
fetchAndUpdateUserTotals ({ commit, state }) { fetchAndUpdateUserTotals ({ commit, state }) {
clearTimeout(state.fetchTotalsTimeout) clearTimeout(state.fetchTotalsTimeout)
state.fetchTotalsTimeout = setTimeout(() => { state.fetchTotalsTimeout = setTimeout(() => {
axios.post('/api/user/totals') // load extended options on initial load
let postData = {
extendedOptions: !state.userTotals
}
axios.post('/api/user/totals', postData)
.then( ({data}) => { .then( ({data}) => {
commit('setUserTotals', data) commit('setUserTotals', data)
}) })

View File

@ -2,7 +2,7 @@ let db = require('@config/database')
let Note = require('@models/Note') let Note = require('@models/Note')
let MetricTracking = module.exports = {} let MetricTracking = module.exports = {};
MetricTracking.get = (userId, masterKey) => { MetricTracking.get = (userId, masterKey) => {
@ -23,31 +23,36 @@ MetricTracking.get = (userId, masterKey) => {
}) })
} else { } else {
//Or create a new note return resolve('no data')
let finalId = null
return Note.create(userId, 'Metric Tracking', '', masterKey)
.then(insertedId => {
finalId = insertedId
db.promise().query('UPDATE note SET quick_note = 2 WHERE id = ? AND user_id = ?',[insertedId, userId])
.then((rows, fields) => {
const note = Note.get(userId, finalId, masterKey)
.then(noteData => {
return resolve(noteData)
})
})
})
} }
}) })
.catch(console.log) .catch(console.log)
}) })
} }
MetricTracking.save = (userId, cycleData, masterKey) => { MetricTracking.create = (userId, masterKey) => {
return new Promise((resolve, reject) => {
let finalId = null
return Note.create(userId, 'Metric Tracking', '', masterKey)
.then(insertedId => {
finalId = insertedId
db.promise().query('UPDATE note SET quick_note = 2 WHERE id = ? AND user_id = ?',[insertedId, userId])
.then((rows, fields) => {
const note = Note.get(userId, finalId, masterKey)
.then(noteData => {
return resolve(noteData)
})
})
})
.catch(console.log)
})
}
MetricTracking.save = (userId, metricData, masterKey) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let finalId = null let finalId = null
@ -55,7 +60,7 @@ MetricTracking.save = (userId, cycleData, masterKey) => {
MetricTracking.get(userId, masterKey) MetricTracking.get(userId, masterKey)
.then(noteObject => { .then(noteObject => {
return Note.update(userId, noteObject.id, cycleData, noteObject.title, noteObject.color, noteObject.pinned, noteObject.archived, null, masterKey) return Note.update(userId, noteObject.id, metricData, noteObject.title, noteObject.color, noteObject.pinned, noteObject.archived, null, masterKey)
}) })
.then( saveResults => { .then( saveResults => {

View File

@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
let User = module.exports = {} let User = module.exports = {}
const version = '3.6.2' const version = '3.6.3'
//Login a user, if that user does not exist create them //Login a user, if that user does not exist create them
//Issues login token //Issues login token
@ -193,13 +193,13 @@ User.register = (username, password) => {
} }
//Counts notes, pinned notes, archived notes, shared notes, unread notes, total files and types //Counts notes, pinned notes, archived notes, shared notes, unread notes, total files and types
User.getCounts = (userId) => { User.getCounts = (userId, extendedOptions) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let countTotals = { let countTotals = {
tags: {} tags: {}
} }
const userHash = cs.hash(String(userId)).toString('base64') // const userHash = cs.hash(String(userId)).toString('base64')
db.promise().query( db.promise().query(
`SELECT `SELECT
@ -279,7 +279,38 @@ User.getCounts = (userId) => {
countTotals['currentVersion'] = version countTotals['currentVersion'] = version
resolve(countTotals) // Allow for extended options set on page load
if(extendedOptions){
db.promise().query(
`SELECT updated FROM note
JOIN note_raw_text ON note_raw_text.id = note.note_raw_text_id
WHERE note.quick_note = 2
AND user_id = ?`, [userId])
.then( (rows, fields) => {
if(rows[0][0] && rows[0][0].updated){
const lastOpened = rows[0][0].updated
const timeDiff = Math.round(((+new Date) - (lastOpened))/1000)
const hoursInSeconds = (12 * 60 * 60) //12 hours
// Show metric tracking button if its been 12 hours since last entry
if(lastOpened && timeDiff > hoursInSeconds){
countTotals['showTrackMetricsButton'] = true
}
}
resolve(countTotals)
})
} else {
resolve(countTotals)
}
}) })
}) })

View File

@ -25,12 +25,16 @@ router.use(function setUserId (req, res, next) {
} }
}) })
//Get quick note text
router.post('/get', function (req, res) { router.post('/get', function (req, res) {
MetricTracking.get(userId, masterKey) MetricTracking.get(userId, masterKey)
.then( data => res.send(data) ) .then( data => res.send(data) )
}) })
router.post('/create', function (req, res) {
MetricTracking.create(userId, masterKey)
.then( data => res.send(data) )
})
//Push text to quick note //Push text to quick note
router.post('/save', function (req, res) { router.post('/save', function (req, res) {
MetricTracking.save(userId, req.body.cycleData, masterKey) MetricTracking.save(userId, req.body.cycleData, masterKey)

View File

@ -53,7 +53,7 @@ router.post('/revokesessions', function(req, res) {
// fetch counts of users notes // fetch counts of users notes
router.post('/totals', function (req, res) { router.post('/totals', function (req, res) {
User.getCounts(req.headers.userId) User.getCounts(req.headers.userId, req.body.extendedOptions)
.then( countsObject => res.send( countsObject )) .then( countsObject => res.send( countsObject ))
}) })

View File

@ -1,4 +1,7 @@
#!/bin/sh #!/bin/bash
# Setup env variables
source ~/.env
# Send updated dynamic IP address to Namecheap, in order to update subdomains. # Send updated dynamic IP address to Namecheap, in order to update subdomains.
# This uses curl (separate pkg) to send the change; Namecheap automatically detects source IP if the ip field (like domain, password) .. # This uses curl (separate pkg) to send the change; Namecheap automatically detects source IP if the ip field (like domain, password) ..
@ -9,12 +12,7 @@ info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
info "Starting IP update for subdomains" info "Starting IP update for subdomains"
PASSWORD="***REMOVED***" echo "https://dynamicdns.park-your-domain.com/update?host=$DYDNS_DOMAIN&domain=$DYDNS_HOST&password=$DYDNS_PASSWORD"
HOST="maxg.cc" curl "https://dynamicdns.park-your-domain.com/update?host=$DYDNS_DOMAIN&domain=$DYDNS_HOST&password=$DYDNS_PASSWORD"
SUBDOMAIN="x.maxg.cc"
#echo "https://dynamicdns.park-your-domain.com/update?host=$SUBDOMAIN&domain=$HOST&password=$PASSWORD"
curl "https://dynamicdns.park-your-domain.com/update?host=$SUBDOMAIN&domain=$HOST&password=$PASSWORD"
info "IP update done" info "IP update done"