client/general: respect privileges
This commit is contained in:
		
							parent
							
								
									0842d90ca2
								
							
						
					
					
						commit
						7566d2e0f3
					
				@ -28,7 +28,11 @@
 | 
			
		||||
                        <span class='vim-nav-hint'>Back to view mode</span>
 | 
			
		||||
                    </a>
 | 
			
		||||
                <% } else { %>
 | 
			
		||||
                    <a href='/post/<%= ctx.post.id %>/edit'>
 | 
			
		||||
                    <% if (ctx.canEditPosts) { %>
 | 
			
		||||
                        <a href='/post/<%= ctx.post.id %>/edit'>
 | 
			
		||||
                    <% } else { %>
 | 
			
		||||
                        <a class='inactive'>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                        <i class='fa fa-pencil'></i>
 | 
			
		||||
                        <span class='vim-nav-hint'>Edit post</span>
 | 
			
		||||
                    </a>
 | 
			
		||||
 | 
			
		||||
@ -39,30 +39,42 @@
 | 
			
		||||
 | 
			
		||||
    <section class='social'>
 | 
			
		||||
        <div class='score'>
 | 
			
		||||
            <a class='upvote' href='#'>
 | 
			
		||||
                <% if (ctx.post.ownScore == 1) { %>
 | 
			
		||||
                    <i class='fa fa-thumbs-up'></i>
 | 
			
		||||
                <% } else { %>
 | 
			
		||||
            <% if (ctx.canScorePosts) { %>
 | 
			
		||||
                <a class='upvote' href='#'>
 | 
			
		||||
                    <% if (ctx.post.ownScore == 1) { %>
 | 
			
		||||
                        <i class='fa fa-thumbs-up'></i>
 | 
			
		||||
                    <% } else { %>
 | 
			
		||||
                        <i class='fa fa-thumbs-o-up'></i>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                    <span class='hint'></span>
 | 
			
		||||
                </a>
 | 
			
		||||
            <% } else { %>
 | 
			
		||||
                <a class='upvote inactive'>
 | 
			
		||||
                    <i class='fa fa-thumbs-o-up'></i>
 | 
			
		||||
                <% } %>
 | 
			
		||||
                <span class='hint'></span>
 | 
			
		||||
            </a>
 | 
			
		||||
                </a>
 | 
			
		||||
            <% } %>
 | 
			
		||||
            <span class='value'><%= ctx.post.score %></span>
 | 
			
		||||
            <a class='downvote' href='#'>
 | 
			
		||||
                <% if (ctx.post.ownScore == -1) { %>
 | 
			
		||||
                    <i class='fa fa-thumbs-down'></i>
 | 
			
		||||
                <% } else { %>
 | 
			
		||||
                    <i class='fa fa-thumbs-o-down'></i>
 | 
			
		||||
                <% } %>
 | 
			
		||||
                <span class='hint'></span>
 | 
			
		||||
            </a>
 | 
			
		||||
            <% if (ctx.canScorePosts) { %>
 | 
			
		||||
                <a class='downvote' href='#'>
 | 
			
		||||
                    <% if (ctx.post.ownScore == -1) { %>
 | 
			
		||||
                        <i class='fa fa-thumbs-down'></i>
 | 
			
		||||
                    <% } else { %>
 | 
			
		||||
                        <i class='fa fa-thumbs-o-down'></i>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                    <span class='hint'></span>
 | 
			
		||||
                </a>
 | 
			
		||||
            <% } %>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div class='fav'>
 | 
			
		||||
            <% if (ctx.post.ownFavorite) { %>
 | 
			
		||||
                <a class='remove-favorite' href='#'><i class='fa fa-heart'></i></a>
 | 
			
		||||
            <% if (ctx.canFavoritePosts) { %>
 | 
			
		||||
                <% if (ctx.post.ownFavorite) { %>
 | 
			
		||||
                    <a class='remove-favorite' href='#'><i class='fa fa-heart'></i></a>
 | 
			
		||||
                <% } else { %>
 | 
			
		||||
                    <a class='add-favorite' href='#'><i class='fa fa-heart-o'></i></a>
 | 
			
		||||
                <% } %>
 | 
			
		||||
            <% } else { %>
 | 
			
		||||
                <a class='add-favorite' href='#'><i class='fa fa-heart-o'></i></a>
 | 
			
		||||
                <a class='add-favorite inactive'><i class='fa fa-heart-o'></i></a>
 | 
			
		||||
            <% } %>
 | 
			
		||||
            <span class='value'><%= ctx.post.favoriteCount %></span>
 | 
			
		||||
        </div>
 | 
			
		||||
@ -74,12 +86,20 @@
 | 
			
		||||
    <ul><!--
 | 
			
		||||
        --><% for (let tag of ctx.post.tags) { %><!--
 | 
			
		||||
            --><li><!--
 | 
			
		||||
                --><% if (ctx.canViewTags) { %><!--
 | 
			
		||||
                --><a href='/tag/<%= tag %>' class='tag-<%= ctx.getTagCategory(tag) %>'><!--
 | 
			
		||||
                    --><i class='fa fa-tag'></i><!--
 | 
			
		||||
                --></a><!--
 | 
			
		||||
                --><a href='/posts/text=<%= tag %>' class='tag-<%= ctx.getTagCategory(tag) %>'><!--
 | 
			
		||||
                --><% } %><!--
 | 
			
		||||
                --><% if (ctx.canListPosts) { %><!--
 | 
			
		||||
                    --></a><!--
 | 
			
		||||
                --><% } %><!--
 | 
			
		||||
                --><% if (ctx.canListPosts) { %><!--
 | 
			
		||||
                    --><a href='/posts/text=<%= tag %>' class='tag-<%= ctx.getTagCategory(tag) %>'><!--
 | 
			
		||||
                --><% } %><!--
 | 
			
		||||
                    --><%= tag %><!--
 | 
			
		||||
                --></a><!--
 | 
			
		||||
                --><% if (ctx.canListPosts) { %><!--
 | 
			
		||||
                    --></a><!--
 | 
			
		||||
                --><% } %><!--
 | 
			
		||||
                --><span class='count'><%= ctx.getTagUsages(tag) %></span><!--
 | 
			
		||||
            --></li><!--
 | 
			
		||||
        --><% } %><!--
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,11 @@
 | 
			
		||||
        <ul>
 | 
			
		||||
            <% for (let post of ctx.results) { %>
 | 
			
		||||
                <li>
 | 
			
		||||
                    <a href='/post/<%= post.id %>' title='@<%= post.id %> (<%= post.type %>)

Tags: <%= post.tags.map(tag => '#' + tag).join(' ') %>'>
 | 
			
		||||
                    <% if (ctx.canViewPosts) { %>
 | 
			
		||||
                        <a href='/post/<%= post.id %>' title='@<%= post.id %> (<%= post.type %>)

Tags: <%= post.tags.map(tag => '#' + tag).join(' ') %>'>
 | 
			
		||||
                    <% } else { %>
 | 
			
		||||
                        <a>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                        <%= ctx.makeThumbnail(post.thumbnailUrl) %>
 | 
			
		||||
                        <span class='type' data-type='<%= post.type %>'>
 | 
			
		||||
                            <%= post.type %>
 | 
			
		||||
 | 
			
		||||
@ -3,9 +3,22 @@
 | 
			
		||||
        --><% for (let user of ctx.results) { %><!--
 | 
			
		||||
            --><li>
 | 
			
		||||
                <div class='wrapper'>
 | 
			
		||||
                    <a class='image' href='/user/<%= user.name %>'><%= ctx.makeThumbnail(user.avatarUrl) %></a>
 | 
			
		||||
                    <% if (ctx.canViewUsers) { %>
 | 
			
		||||
                        <a class='image' href='/user/<%= user.name %>'>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                        <%= ctx.makeThumbnail(user.avatarUrl) %>
 | 
			
		||||
                    <% if (ctx.canViewUsers) { %>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    <% } %>
 | 
			
		||||
                    <div class='details'>
 | 
			
		||||
                        <a href='/user/<%= user.name %>'><%= user.name %></a><br/>
 | 
			
		||||
                        <% if (ctx.canViewUsers) { %>
 | 
			
		||||
                            <a href='/user/<%= user.name %>'>
 | 
			
		||||
                        <% } %>
 | 
			
		||||
                            <%= user.name %>
 | 
			
		||||
                        <% if (ctx.canViewUsers) { %>
 | 
			
		||||
                            </a>
 | 
			
		||||
                        <% } %>
 | 
			
		||||
                        <br/>
 | 
			
		||||
                        Registered: <%= ctx.makeRelativeTime(user.creationTime) %><br/>
 | 
			
		||||
                        Last seen: <%= ctx.makeRelativeTime(user.lastLoginTime) %>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,17 @@ class PageController {
 | 
			
		||||
 | 
			
		||||
    run(ctx) {
 | 
			
		||||
        this._pageView.unrender();
 | 
			
		||||
 | 
			
		||||
        ctx.headerContext = ctx.headerContext || {};
 | 
			
		||||
        Object.assign(ctx.headerContext, {
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        ctx.pageContext = ctx.pageContext || {};
 | 
			
		||||
        Object.assign(ctx.pageContext, {
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._pageView.render(ctx);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,7 +42,9 @@ class PostsController {
 | 
			
		||||
        topNavController.activate('posts');
 | 
			
		||||
 | 
			
		||||
        pageController.run({
 | 
			
		||||
            state: ctx.state,
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            clientUrl: '/posts/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            requestPage: page => {
 | 
			
		||||
                const text = this._decorateSearchQuery(ctx.searchQuery.text);
 | 
			
		||||
                return api.get(
 | 
			
		||||
@ -50,11 +52,11 @@ class PostsController {
 | 
			
		||||
                    `id,type,tags,score,favoriteCount,` +
 | 
			
		||||
                    `commentCount,thumbnailUrl`);
 | 
			
		||||
            },
 | 
			
		||||
            clientUrl: '/posts/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            headerRenderer: this._postsHeaderView,
 | 
			
		||||
            pageRenderer: this._postsPageView,
 | 
			
		||||
            pageContext: {
 | 
			
		||||
                canViewPosts: api.hasPrivilege('posts:view'),
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -71,6 +73,7 @@ class PostsController {
 | 
			
		||||
                editMode: editMode,
 | 
			
		||||
                nextPostId: aroundResponse.next ? aroundResponse.next.id : null,
 | 
			
		||||
                prevPostId: aroundResponse.prev ? aroundResponse.prev.id : null,
 | 
			
		||||
                canEditPosts: api.hasPrivilege('posts:edit'),
 | 
			
		||||
            });
 | 
			
		||||
        }, response => {
 | 
			
		||||
            this._emptyView.render();
 | 
			
		||||
 | 
			
		||||
@ -202,18 +202,19 @@ class TagsController {
 | 
			
		||||
        topNavController.activate('tags');
 | 
			
		||||
 | 
			
		||||
        pageController.run({
 | 
			
		||||
            state: ctx.state,
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            clientUrl: '/tags/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            requestPage: page => {
 | 
			
		||||
                const text = ctx.searchQuery.text;
 | 
			
		||||
                return api.get(
 | 
			
		||||
                    `/tags/?query=${text}&page=${page}&pageSize=50`);
 | 
			
		||||
            },
 | 
			
		||||
            clientUrl: '/tags/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            headerRenderer: this._tagsHeaderView,
 | 
			
		||||
            pageRenderer: this._tagsPageView,
 | 
			
		||||
            canEditTagCategories: api.hasPrivilege('tagCategories:edit'),
 | 
			
		||||
            headerContext: {
 | 
			
		||||
                canEditTagCategories: api.hasPrivilege('tagCategories:edit'),
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -65,17 +65,19 @@ class UsersController {
 | 
			
		||||
        topNavController.activate('users');
 | 
			
		||||
 | 
			
		||||
        pageController.run({
 | 
			
		||||
            state: ctx.state,
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            clientUrl: '/users/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            requestPage: page => {
 | 
			
		||||
                const text = ctx.searchQuery.text;
 | 
			
		||||
                return api.get(
 | 
			
		||||
                    `/users/?query=${text}&page=${page}&pageSize=30`);
 | 
			
		||||
            },
 | 
			
		||||
            clientUrl: '/users/' + misc.formatSearchQuery({
 | 
			
		||||
                text: ctx.searchQuery.text, page: '{page}'}),
 | 
			
		||||
            searchQuery: ctx.searchQuery,
 | 
			
		||||
            headerRenderer: this._usersHeaderView,
 | 
			
		||||
            pageRenderer: this._usersPageView,
 | 
			
		||||
            pageContext: {
 | 
			
		||||
                canViewUsers: api.hasPrivilege('users:view'),
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,10 @@ class PostReadonlySidebarControl {
 | 
			
		||||
            post: this._post,
 | 
			
		||||
            getTagCategory: this._getTagCategory,
 | 
			
		||||
            getTagUsages: this._getTagUsages,
 | 
			
		||||
            canListPosts: api.hasPrivilege('posts:list'),
 | 
			
		||||
            canScorePosts: api.hasPrivilege('posts:score'),
 | 
			
		||||
            canFavoritePosts: api.hasPrivilege('posts:favorite'),
 | 
			
		||||
            canViewTags: api.hasPrivilege('tags:view'),
 | 
			
		||||
        });
 | 
			
		||||
        const upvoteButton = sourceNode.querySelector('.upvote');
 | 
			
		||||
        const downvoteButton = sourceNode.querySelector('.downvote')
 | 
			
		||||
@ -29,12 +33,16 @@ class PostReadonlySidebarControl {
 | 
			
		||||
        const fitWidthButton = sourceNode.querySelector('.fit-width')
 | 
			
		||||
        const fitHeightButton = sourceNode.querySelector('.fit-height');
 | 
			
		||||
 | 
			
		||||
        upvoteButton.addEventListener(
 | 
			
		||||
            'click', this._eventRequestProxy(
 | 
			
		||||
                () => this._setScore(this._post.ownScore === 1 ? 0 : 1)));
 | 
			
		||||
        downvoteButton.addEventListener(
 | 
			
		||||
            'click', this._eventRequestProxy(
 | 
			
		||||
                () => this._setScore(this._post.ownScore === -1 ? 0 : -1)));
 | 
			
		||||
        if (upvoteButton) {
 | 
			
		||||
            upvoteButton.addEventListener(
 | 
			
		||||
                'click', this._eventRequestProxy(
 | 
			
		||||
                    () => this._setScore(this._post.ownScore === 1 ? 0 : 1)));
 | 
			
		||||
        }
 | 
			
		||||
        if (downvoteButton) {
 | 
			
		||||
            downvoteButton.addEventListener(
 | 
			
		||||
                'click', this._eventRequestProxy(
 | 
			
		||||
                    () => this._setScore(this._post.ownScore === -1 ? 0 : -1)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (addFavButton) {
 | 
			
		||||
            addFavButton.addEventListener(
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
require('../util/polyfill.js');
 | 
			
		||||
const api = require('../api.js');
 | 
			
		||||
const templates = require('../templates.js');
 | 
			
		||||
const tags = require('../tags.js');
 | 
			
		||||
const events = require('../events.js');
 | 
			
		||||
@ -137,25 +138,35 @@ function makeColorInput(options) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makePostLink(id) {
 | 
			
		||||
    return makeNonVoidElement('a', {
 | 
			
		||||
        'href': '/post/' + id,
 | 
			
		||||
    }, '@' + id);
 | 
			
		||||
    const text = '@' + id;
 | 
			
		||||
    return api.hasPrivilege('posts:view') ?
 | 
			
		||||
        makeNonVoidElement('a', {'href': '/post/' + id}, text) :
 | 
			
		||||
        text;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makeTagLink(name) {
 | 
			
		||||
    const tag = tags.getTagByName(name);
 | 
			
		||||
    let category = tag ? tag.category : 'unknown';
 | 
			
		||||
    return makeNonVoidElement('a', {
 | 
			
		||||
        'href': '/tag/' + name,
 | 
			
		||||
        'class': 'tag-' + category,
 | 
			
		||||
    }, name);
 | 
			
		||||
    const category = tag ? tag.category : 'unknown';
 | 
			
		||||
    return api.hasPrivilege('tags:view') ?
 | 
			
		||||
        makeNonVoidElement(
 | 
			
		||||
            'a', {
 | 
			
		||||
                'href': '/tag/' + name,
 | 
			
		||||
                'class': 'tag-' + category,
 | 
			
		||||
            }, name) :
 | 
			
		||||
        makeNonVoidElement(
 | 
			
		||||
            'span', {
 | 
			
		||||
                'class': 'tag-' + category,
 | 
			
		||||
            },
 | 
			
		||||
            name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makeUserLink(user) {
 | 
			
		||||
    let link = api.hasPrivilege('users:view') ?
 | 
			
		||||
        makeNonVoidElement('a', {'href': '/user/' + user.name}, user.name) :
 | 
			
		||||
        user.name;
 | 
			
		||||
    return makeNonVoidElement('span', {class: 'user'},
 | 
			
		||||
        makeThumbnail(user.avatarUrl) +
 | 
			
		||||
        makeNonVoidElement(
 | 
			
		||||
            'a', {'href': '/user/' + user.name}, user.name));
 | 
			
		||||
        link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function makeFlexboxAlign(options) {
 | 
			
		||||
 | 
			
		||||
@ -24,9 +24,8 @@ class EndlessPageView {
 | 
			
		||||
        this._active = true;
 | 
			
		||||
        this._working = 0;
 | 
			
		||||
 | 
			
		||||
        let headerRendererCtx = ctx;
 | 
			
		||||
        headerRendererCtx.target = pageHeaderHolder;
 | 
			
		||||
        ctx.headerRenderer.render(headerRendererCtx);
 | 
			
		||||
        ctx.headerContext.target = pageHeaderHolder;
 | 
			
		||||
        ctx.headerRenderer.render(ctx.headerContext);
 | 
			
		||||
 | 
			
		||||
        const threshold = window.innerHeight / 3;
 | 
			
		||||
 | 
			
		||||
@ -115,10 +114,10 @@ class EndlessPageView {
 | 
			
		||||
                });
 | 
			
		||||
                pageNode.setAttribute('data-page', pageNumber);
 | 
			
		||||
 | 
			
		||||
                let pageRendererCtx = response;
 | 
			
		||||
                pageRendererCtx.target = pageNode.querySelector(
 | 
			
		||||
                Object.assign(ctx.pageContext, response);
 | 
			
		||||
                ctx.pageContext.target = pageNode.querySelector(
 | 
			
		||||
                    '.page-content-holder');
 | 
			
		||||
                ctx.pageRenderer.render(pageRendererCtx);
 | 
			
		||||
                ctx.pageRenderer.render(ctx.pageContext);
 | 
			
		||||
 | 
			
		||||
                if (pageNumber < this.minPageShown ||
 | 
			
		||||
                        this.minPageShown === null) {
 | 
			
		||||
 | 
			
		||||
@ -69,14 +69,13 @@ class ManualPageView {
 | 
			
		||||
        const pageNav = source.querySelector('.page-nav');
 | 
			
		||||
        const currentPage = ctx.searchQuery.page;
 | 
			
		||||
 | 
			
		||||
        let headerRendererCtx = ctx;
 | 
			
		||||
        headerRendererCtx.target = pageHeaderHolder;
 | 
			
		||||
        ctx.headerRenderer.render(headerRendererCtx);
 | 
			
		||||
        ctx.headerContext.target = pageHeaderHolder;
 | 
			
		||||
        ctx.headerRenderer.render(ctx.headerContext);
 | 
			
		||||
 | 
			
		||||
        ctx.requestPage(currentPage).then(response => {
 | 
			
		||||
            let pageRendererCtx = response;
 | 
			
		||||
            pageRendererCtx.target = pageContentHolder;
 | 
			
		||||
            ctx.pageRenderer.render(pageRendererCtx);
 | 
			
		||||
            Object.assign(ctx.pageContext, response);
 | 
			
		||||
            ctx.pageContext.target = pageContentHolder;
 | 
			
		||||
            ctx.pageRenderer.render(ctx.pageContext);
 | 
			
		||||
 | 
			
		||||
            const totalPages = Math.ceil(response.total / response.pageSize);
 | 
			
		||||
            const pageNumbers = _getVisiblePageNumbers(currentPage, totalPages);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user