Added option to create white-list of FLO IDs allowed to send publishing requests from CC to RM Times
This commit is contained in:
parent
1fd125f284
commit
7fb27e728c
17
css/main.css
17
css/main.css
@ -986,6 +986,23 @@ theme-toggle {
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cc_section {
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
width: min(28rem, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flo-id-card {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
.flo-id-card .flo-id {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.flo-id-card .icon-only {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
#user_popup {
|
#user_popup {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|||||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -942,6 +942,21 @@ theme-toggle {
|
|||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#cc_section {
|
||||||
|
padding: 1.5rem 0;
|
||||||
|
width: min(28rem, 100%);
|
||||||
|
}
|
||||||
|
.flo-id-card {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
.flo-id {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.icon-only {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
#user_popup {
|
#user_popup {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
header {
|
header {
|
||||||
|
|||||||
122
index.html
122
index.html
@ -237,9 +237,7 @@
|
|||||||
<section class="hero-section">
|
<section class="hero-section">
|
||||||
<h1 id="article_title"></h1>
|
<h1 id="article_title"></h1>
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<div class="flex flex-wrap">
|
<time id="published_time"></time>
|
||||||
<time id="published_time" style="white-space: pre;"></time><time id="updated_time"></time>
|
|
||||||
</div>
|
|
||||||
<span class="bullet-point"></span><span id="reading_time" style="white-space: nowrap;"></span>
|
<span class="bullet-point"></span><span id="reading_time" style="white-space: nowrap;"></span>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -273,6 +271,7 @@
|
|||||||
<strip-option value="analytic" selected>Analytics</strip-option>
|
<strip-option value="analytic" selected>Analytics</strip-option>
|
||||||
<strip-option value="request">Requests</strip-option>
|
<strip-option value="request">Requests</strip-option>
|
||||||
<strip-option value="writers">Writers</strip-option>
|
<strip-option value="writers">Writers</strip-option>
|
||||||
|
<strip-option value="cc">CC</strip-option>
|
||||||
</strip-select>
|
</strip-select>
|
||||||
</div>
|
</div>
|
||||||
<section id="analytic_section" class="admin-section">
|
<section id="analytic_section" class="admin-section">
|
||||||
@ -295,6 +294,23 @@
|
|||||||
<ul id="writers_list" class="grid gap-1-5 observe-empty-state"></ul>
|
<ul id="writers_list" class="grid gap-1-5 observe-empty-state"></ul>
|
||||||
<p class="empty-state">No writers</p>
|
<p class="empty-state">No writers</p>
|
||||||
</section>
|
</section>
|
||||||
|
<section id="cc_section" class="admin-section hide grid gap-1-5">
|
||||||
|
<div class="grid gap-1-5">
|
||||||
|
<div class="grid gap-0-5">
|
||||||
|
<h4>Approve FLO IDs</h4>
|
||||||
|
<p>Add FLO IDs that are allowed to submit article publishing requests from CC.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<sm-form>
|
||||||
|
<div class="flex">
|
||||||
|
<sm-input id="get_id_to_add" placeholder="Add FLO IDs" class="w-100" required></sm-input>
|
||||||
|
<sm-button variant="primary" onclick="addApprovedID()">Add</sm-button>
|
||||||
|
</div>
|
||||||
|
</sm-form>
|
||||||
|
</div>
|
||||||
|
<ul id="approved_ids" class="grid gap-0-5 observe-empty-state"></ul>
|
||||||
|
<p class="empty-state">No approved FLO IDs</p>
|
||||||
|
</section>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<sm-popup id="sign_in_popup">
|
<sm-popup id="sign_in_popup">
|
||||||
@ -628,6 +644,19 @@
|
|||||||
<sm-copy class="writer-flo-id"></sm-copy>
|
<sm-copy class="writer-flo-id"></sm-copy>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
<template id="flo_id_card_template">
|
||||||
|
<li class="flo-id-card flex align-center">
|
||||||
|
<div class="flo-id"></div>
|
||||||
|
<button class="icon-only delete-flo-id" title="Delete approved FLO ID">
|
||||||
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
|
||||||
|
fill="#000000">
|
||||||
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
||||||
|
<path
|
||||||
|
d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
@ -1080,8 +1109,11 @@
|
|||||||
return clone
|
return clone
|
||||||
},
|
},
|
||||||
requestCard(details) {
|
requestCard(details) {
|
||||||
const { message: { articleID, category, title }, time, vectorClock } = details
|
console.log(details)
|
||||||
if (!floGlobals.appObjects.adminData.publishedVc.hasOwnProperty(vectorClock) && !floGlobals.appObjects.adminData.rejectedVc.hasOwnProperty(vectorClock)) {
|
const { senderID, message: { articleID, category, title }, time, vectorClock } = details
|
||||||
|
const { publishedVc, rejectedVc, approvedID } = floGlobals.appObjects.adminData
|
||||||
|
const shouldRender = approvedID.hasOwnProperty(senderID) && !publishedVc.hasOwnProperty(vectorClock) && !rejectedVc.hasOwnProperty(vectorClock)
|
||||||
|
if (shouldRender) {
|
||||||
const clone = getRef('request_template').content.cloneNode(true).firstElementChild
|
const clone = getRef('request_template').content.cloneNode(true).firstElementChild
|
||||||
clone.dataset.vc = vectorClock
|
clone.dataset.vc = vectorClock
|
||||||
clone.querySelector('.request-card__title').textContent = title
|
clone.querySelector('.request-card__title').textContent = title
|
||||||
@ -1109,6 +1141,12 @@
|
|||||||
clone.querySelector('.writer-flo-id').setAttribute('value', writerID)
|
clone.querySelector('.writer-flo-id').setAttribute('value', writerID)
|
||||||
return clone
|
return clone
|
||||||
},
|
},
|
||||||
|
floIDCard(floID) {
|
||||||
|
const clone = getRef('flo_id_card_template').content.cloneNode(true).firstElementChild
|
||||||
|
clone.dataset.floId = floID
|
||||||
|
clone.querySelector('.flo-id').textContent = floID
|
||||||
|
return clone
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const getArticles = async () => {
|
const getArticles = async () => {
|
||||||
@ -1182,17 +1220,15 @@
|
|||||||
const allArticles = await compactIDB.readData('appObjects', 'articlesContent')
|
const allArticles = await compactIDB.readData('appObjects', 'articlesContent')
|
||||||
const { title, published, readTime, contributors, updated } = floGlobals.appObjects.rmTimes.articles[articleID]
|
const { title, published, readTime, contributors, updated } = floGlobals.appObjects.rmTimes.articles[articleID]
|
||||||
getRef('article_title').textContent = title
|
getRef('article_title').textContent = title
|
||||||
getRef('published_time').textContent = `Published ${getFormattedTime(published, 'date-only')}${updated ? ", " : ''}`
|
getRef('published_time').textContent = `Published ${getFormattedTime(published, 'date-only')}${updated ? `, Updated ${relativeTime.from(updated)}` : ''}`
|
||||||
if (updated)
|
|
||||||
getRef('updated_time').textContent = `Updated ${relativeTime.from(updated)}`
|
|
||||||
getRef('reading_time').textContent = `${readTime} Min read`
|
getRef('reading_time').textContent = `${readTime} Min read`
|
||||||
getRef('article_body').innerHTML = allArticles[articleID]
|
getRef('article_body').innerHTML = allArticles[articleID]
|
||||||
getRef('article_body').querySelectorAll('h3').forEach(heading => {
|
getRef('article_body').querySelectorAll('h3').forEach(heading => {
|
||||||
const headingText = heading.textContent
|
const headingText = heading.textContent
|
||||||
const headingID = floCrypto.randString(8)
|
const headingID = `s${floCrypto.randString(8)}`
|
||||||
heading.id = headingID
|
heading.id = headingID
|
||||||
frag.append(createElement('li', {
|
frag.append(createElement('li', {
|
||||||
innerHTML: `<button data-heading-id="${headingID}">${headingText}</button>`
|
innerHTML: `<button class="heading-shortcut" data-heading-id="${headingID}">${headingText}</button>`
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
getRef('article_map_container').innerHTML = ''
|
getRef('article_map_container').innerHTML = ''
|
||||||
@ -1499,6 +1535,16 @@
|
|||||||
tempCount.remove()
|
tempCount.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
getRef('article').addEventListener('click', (e) => {
|
||||||
|
if (e.target.closest('.heading-shortcut')) {
|
||||||
|
const button = e.target.closest('.heading-shortcut');
|
||||||
|
const headingID = button.dataset.headingId;
|
||||||
|
const heading = getRef('article_body').querySelector(`#${headingID}`)
|
||||||
|
heading.scrollIntoView({
|
||||||
|
behavior: 'smooth'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
getRef('upvote_button').addEventListener('click', debounce(() => {
|
getRef('upvote_button').addEventListener('click', debounce(() => {
|
||||||
if (typeof myFloID !== 'undefined') {
|
if (typeof myFloID !== 'undefined') {
|
||||||
floCloudAPI.sendGeneralData({
|
floCloudAPI.sendGeneralData({
|
||||||
@ -1633,23 +1679,26 @@
|
|||||||
if (card)
|
if (card)
|
||||||
frag.prepend(card)
|
frag.prepend(card)
|
||||||
}
|
}
|
||||||
floCloudAPI.updateObjectData('adminData')
|
|
||||||
getRef('publishing_requests').innerHTML = ''
|
getRef('publishing_requests').innerHTML = ''
|
||||||
getRef('publishing_requests').append(frag)
|
getRef('publishing_requests').append(frag)
|
||||||
|
|
||||||
for (const articleKey in floGlobals.appObjects.rmTimes.articles) {
|
for (const articleKey in floGlobals.appObjects.rmTimes.articles) {
|
||||||
const card = render.articleRow(articleKey)
|
frag.prepend(render.articleRow(articleKey))
|
||||||
frag.prepend(card)
|
|
||||||
}
|
}
|
||||||
getRef('article_analytics').innerHTML = ''
|
getRef('article_analytics').innerHTML = ''
|
||||||
getRef('article_analytics').append(frag)
|
getRef('article_analytics').append(frag)
|
||||||
|
|
||||||
for (const articleKey in floGlobals.appObjects.rmTimes.articleWriters) {
|
for (const articleKey in floGlobals.appObjects.rmTimes.articleWriters) {
|
||||||
const card = render.writerCard(articleKey)
|
frag.prepend(render.writerCard(articleKey))
|
||||||
frag.prepend(card)
|
|
||||||
}
|
}
|
||||||
getRef('writers_list').innerHTML = ''
|
getRef('writers_list').innerHTML = ''
|
||||||
getRef('writers_list').append(frag)
|
getRef('writers_list').append(frag)
|
||||||
|
|
||||||
|
for (const floID in floGlobals.appObjects.adminData.approvedID) {
|
||||||
|
frag.prepend(render.floIDCard(floID))
|
||||||
|
}
|
||||||
|
getRef('approved_ids').innerHTML = ''
|
||||||
|
getRef('approved_ids').append(frag)
|
||||||
}
|
}
|
||||||
|
|
||||||
function publishArticle(vc) {
|
function publishArticle(vc) {
|
||||||
@ -1932,6 +1981,47 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addApprovedID() {
|
||||||
|
getConfirmation('Approve FLO ID?').then(res => {
|
||||||
|
if (res) {
|
||||||
|
const idToAdd = getRef('get_id_to_add').value.trim()
|
||||||
|
const validIds = idToAdd.split(',').filter(floID => {
|
||||||
|
return (floCrypto.validateAddr(floID) && !floGlobals.appObjects.adminData.approvedID.hasOwnProperty(floID))
|
||||||
|
})
|
||||||
|
if (validIds.length) {
|
||||||
|
const frag = document.createDocumentFragment()
|
||||||
|
validIds.forEach(floID => {
|
||||||
|
floGlobals.appObjects.adminData.approvedID[floID] = true
|
||||||
|
frag.append(render.floIDCard(floID))
|
||||||
|
})
|
||||||
|
getRef('approved_ids').prepend(frag)
|
||||||
|
floCloudAPI.updateObjectData('adminData').then(() => {
|
||||||
|
notify('Approved FLO IDs', 'success')
|
||||||
|
}).catch(error => console.error(error))
|
||||||
|
} else {
|
||||||
|
notify('Given FLO IDs are already added', 'error')
|
||||||
|
}
|
||||||
|
getRef('get_id_to_add').value = ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleApprovedIDsClick(e) {
|
||||||
|
if (e.target.closest('.delete-flo-id')) {
|
||||||
|
const floIdCard = e.target.closest('.flo-id-card');
|
||||||
|
const floID = floIdCard.dataset.floId;
|
||||||
|
getConfirmation('Remove this FLO ID from approved list?').then(res => {
|
||||||
|
if (res) {
|
||||||
|
delete floGlobals.appObjects.adminData.approvedID[floID]
|
||||||
|
floIdCard.remove()
|
||||||
|
floCloudAPI.updateObjectData('adminData').then(() => {
|
||||||
|
notify('Removed FLO ID', 'success')
|
||||||
|
}).catch(error => console.error(error))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getSignedIn() {
|
function getSignedIn() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
getRef('sign_in_button').onclick = () => {
|
getRef('sign_in_button').onclick = () => {
|
||||||
@ -1976,12 +2066,14 @@
|
|||||||
getRef('publishing_requests').addEventListener('click', handleRequestClick);
|
getRef('publishing_requests').addEventListener('click', handleRequestClick);
|
||||||
getRef('article_analytics').addEventListener('click', handleAnalyticsClick);
|
getRef('article_analytics').addEventListener('click', handleAnalyticsClick);
|
||||||
getRef('writers_list').addEventListener('click', handleWritersClick);
|
getRef('writers_list').addEventListener('click', handleWritersClick);
|
||||||
|
getRef('approved_ids').addEventListener('click', handleApprovedIDsClick);
|
||||||
document.querySelectorAll('.admin-option').forEach(elem => elem.classList.remove('hide'));
|
document.querySelectorAll('.admin-option').forEach(elem => elem.classList.remove('hide'));
|
||||||
location.hash = '#/dashboard'
|
location.hash = '#/dashboard'
|
||||||
} else {
|
} else {
|
||||||
getRef('publishing_requests').removeEventListener('click', handleRequestClick)
|
getRef('publishing_requests').removeEventListener('click', handleRequestClick)
|
||||||
getRef('article_analytics').removeEventListener('click', handleAnalyticsClick);
|
getRef('article_analytics').removeEventListener('click', handleAnalyticsClick);
|
||||||
getRef('writers_list').removeEventListener('click', handleWritersClick);
|
getRef('writers_list').removeEventListener('click', handleWritersClick);
|
||||||
|
getRef('approved_ids').removeEventListener('click', handleApprovedIDsClick);
|
||||||
document.querySelectorAll('.admin-option').forEach(elem => elem.classList.add('hide'))
|
document.querySelectorAll('.admin-option').forEach(elem => elem.classList.add('hide'))
|
||||||
}
|
}
|
||||||
console.log(result)
|
console.log(result)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user