Compare commits
2 Commits
51e35b0f11
...
062996bf7c
Author | SHA1 | Date | |
---|---|---|---|
|
062996bf7c | ||
|
5d4376b4e7 |
@ -1,12 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Take all variables in .env and turn them into local variables for this script
|
||||
source ~/.env
|
||||
|
||||
BACKUPDIR="/home/mab/databaseBackupSolidScribe"
|
||||
|
||||
mkdir -p $BACKUPDIR
|
||||
cd $BACKUPDIR
|
||||
|
||||
NOW=$(date +"%Y-%m-%d_%H-%M")
|
||||
ssh mab@solidscribe.com -p 13328 "mysqldump --all-databases --single-transaction --user root -pRootPass1234!" > "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"
|
||||
|
||||
# cp "backup-$NOW.sql" "/mnt/Windows Data/DatabaseBackups/backup-$NOW.sql"
|
||||
|
@ -146,6 +146,9 @@ body {
|
||||
.ui.dividing.header {
|
||||
border-bottom-color: var(--dark_border_color);
|
||||
}
|
||||
.ui.dividing.header > .sub.header {
|
||||
color: var(--dark_border_color);
|
||||
}
|
||||
.ui.icon.input > i.icon {
|
||||
color: var(--text_color);
|
||||
}
|
||||
@ -180,10 +183,15 @@ i.green.icon.icon.icon.icon, i.green.icon.icon.icon.icon.icon {
|
||||
.button {
|
||||
box-shadow: 2px 2px 4px -2px rgba(40, 40, 40, 0.89) !important;
|
||||
transition: all 0.9s ease;
|
||||
position: relative;
|
||||
}
|
||||
.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 {
|
||||
background-color: var(--main-accent);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 111;
|
||||
z-index: 900;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
@ -66,7 +66,7 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
z-index: 100;
|
||||
z-index: 899;
|
||||
cursor: pointer;
|
||||
}
|
||||
.top-menu-bar {
|
||||
@ -526,8 +526,11 @@
|
||||
location.reload(true)
|
||||
},
|
||||
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 index = ( parseInt(this.version.replace(/\./g,'')) % (icons.length))
|
||||
const index = ( parseInt(String(this.version).replace(/\./g,'')) % (icons.length))
|
||||
return icons[index]
|
||||
|
||||
}
|
||||
|
164
client/src/components/ModalComponent.vue
Normal file
164
client/src/components/ModalComponent.vue
Normal 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>
|
@ -35,7 +35,6 @@
|
||||
<i class="search icon"></i>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="floating-button" v-if="searchTerm.length > 0">
|
||||
<i class="big link grey close icon" v-on:click="clear()"></i>
|
||||
</div>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,12 @@
|
||||
animation: fadeorama 16s ease infinite;
|
||||
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 {
|
||||
position: absolute;
|
||||
@ -492,6 +497,8 @@
|
||||
<a target="_blank" href="https://www.maxg.cc">Solid Scribe was created by Max Gialanella</a>
|
||||
</h3>
|
||||
<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>
|
||||
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>
|
||||
|
@ -12,6 +12,12 @@
|
||||
<search-input />
|
||||
</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="ui basic button shrinking"
|
||||
@ -110,7 +116,7 @@
|
||||
</div>
|
||||
<div class="ui small green button" v-on:click="collapseFloatingList = true">
|
||||
<i class="caret square left outline icon"></i>
|
||||
Hide Menu
|
||||
Hide List
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -154,7 +160,8 @@
|
||||
|
||||
</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>
|
||||
</div>
|
||||
|
||||
|
@ -120,7 +120,7 @@ export default new Router({
|
||||
path: '/metrictrack',
|
||||
name: 'Metric Tracking',
|
||||
meta: {title:'Metric Tracking'},
|
||||
component: () => import(/* webpackChunkName: "CycletrackingPage" */ '@/pages/CycletrackingPage')
|
||||
component: () => import(/* webpackChunkName: "MetrictrackingPage" */ '@/pages/MetrictrackingPage')
|
||||
},
|
||||
]
|
||||
})
|
||||
|
@ -10,7 +10,7 @@ export default new Vuex.Store({
|
||||
nightMode: false,
|
||||
isUserOnMobile: false,
|
||||
fetchTotalsTimeout: null,
|
||||
userTotals: null,
|
||||
userTotals: null, // {} // setting this to object breaks reactivity
|
||||
activeSessions: 0,
|
||||
},
|
||||
mutations: {
|
||||
@ -101,8 +101,23 @@ export default new Vuex.Store({
|
||||
state.socket = socket
|
||||
},
|
||||
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
|
||||
const currentVersion = localStorage.getItem('currentVersion')
|
||||
@ -126,6 +141,11 @@ export default new Vuex.Store({
|
||||
setActiveSessions(state, countData){
|
||||
//Count of the number of active socket.io sessions for this user
|
||||
state.activeSessions = countData
|
||||
},
|
||||
hideMetricTrackingReminder(state){
|
||||
if(state.userTotals){
|
||||
state.userTotals['showTrackMetricsButton'] = false
|
||||
}
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
@ -159,7 +179,11 @@ export default new Vuex.Store({
|
||||
fetchAndUpdateUserTotals ({ commit, state }) {
|
||||
clearTimeout(state.fetchTotalsTimeout)
|
||||
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}) => {
|
||||
commit('setUserTotals', data)
|
||||
})
|
||||
|
@ -2,7 +2,7 @@ let db = require('@config/database')
|
||||
|
||||
let Note = require('@models/Note')
|
||||
|
||||
let MetricTracking = module.exports = {}
|
||||
let MetricTracking = module.exports = {};
|
||||
|
||||
|
||||
MetricTracking.get = (userId, masterKey) => {
|
||||
@ -23,31 +23,36 @@ MetricTracking.get = (userId, masterKey) => {
|
||||
})
|
||||
|
||||
} else {
|
||||
//Or create a new note
|
||||
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)
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
return resolve('no data')
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
.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) => {
|
||||
|
||||
let finalId = null
|
||||
@ -55,7 +60,7 @@ MetricTracking.save = (userId, cycleData, masterKey) => {
|
||||
MetricTracking.get(userId, masterKey)
|
||||
.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 => {
|
||||
|
@ -9,7 +9,7 @@ const speakeasy = require('speakeasy')
|
||||
|
||||
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
|
||||
//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
|
||||
User.getCounts = (userId) => {
|
||||
User.getCounts = (userId, extendedOptions) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
let countTotals = {
|
||||
tags: {}
|
||||
}
|
||||
const userHash = cs.hash(String(userId)).toString('base64')
|
||||
// const userHash = cs.hash(String(userId)).toString('base64')
|
||||
|
||||
db.promise().query(
|
||||
`SELECT
|
||||
@ -279,7 +279,38 @@ User.getCounts = (userId) => {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
@ -25,12 +25,16 @@ router.use(function setUserId (req, res, next) {
|
||||
}
|
||||
})
|
||||
|
||||
//Get quick note text
|
||||
router.post('/get', function (req, res) {
|
||||
MetricTracking.get(userId, masterKey)
|
||||
.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
|
||||
router.post('/save', function (req, res) {
|
||||
MetricTracking.save(userId, req.body.cycleData, masterKey)
|
||||
|
@ -53,7 +53,7 @@ router.post('/revokesessions', function(req, res) {
|
||||
|
||||
// fetch counts of users notes
|
||||
router.post('/totals', function (req, res) {
|
||||
User.getCounts(req.headers.userId)
|
||||
User.getCounts(req.headers.userId, req.body.extendedOptions)
|
||||
.then( countsObject => res.send( countsObject ))
|
||||
})
|
||||
|
||||
|
@ -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.
|
||||
# This uses curl (separate pkg) to send the change; Namecheap automatically detects source IP if the ip field (like domain, password) ..
|
||||
@ -9,12 +12,11 @@ info() { printf "\n%s %s\n\n" "$( date )" "$*" >&2; }
|
||||
|
||||
info "Starting IP update for subdomains"
|
||||
|
||||
PASSWORD="12a35d53c2c54d6281265e3e086e541b"
|
||||
HOST="maxg.cc"
|
||||
SUBDOMAIN="x.maxg.cc"
|
||||
echo "https://dynamicdns.park-your-domain.com/update?host=$DYDNS_HOST&domain=$DYDNS_DOMAIN&password=$DYDNS_PASS"
|
||||
|
||||
|
||||
#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"
|
||||
# first subdomain
|
||||
curl "https://dynamicdns.park-your-domain.com/update?host=$DYDNS_HOST&domain=$DYDNS_DOMAIN&password=$DYDNS_PASS"
|
||||
# second subdomain
|
||||
curl "https://dynamicdns.park-your-domain.com/update?host=$DYDNS_HOST2&domain=$DYDNS_DOMAIN&password=$DYDNS_PASS"
|
||||
|
||||
info "IP update done"
|
Loading…
Reference in New Issue
Block a user