From dda30e407aca321f369f27078076d3e05fd28b19 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 21 Sep 2015 16:03:18 -0700 Subject: Added confirmation when users request another verification email; users are no longer redirected after requesting another verification email --- web/react/components/email_verify.jsx | 8 +++++++- web/web.go | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx index 92123956f..4d4d489bb 100644 --- a/web/react/components/email_verify.jsx +++ b/web/react/components/email_verify.jsx @@ -10,12 +10,14 @@ export default class EmailVerify extends React.Component { this.state = {}; } handleResend() { - window.location.href = window.location.href + '&resend=true'; + const newAddress = window.location.href.replace('?resend_success=true', '').replace('&resend_success=true', ''); + window.location.href = newAddress + '&resend=true'; } render() { var title = ''; var body = ''; var resend = ''; + let resendConfirm = ''; if (this.props.isVerified === 'true') { title = global.window.config.SiteName + ' Email Verified'; body =

Your email has been verified! Click -1) { + resendConfirm =


{' Verification email sent.'}

; + } } return ( @@ -41,6 +46,7 @@ export default class EmailVerify extends React.Component {
{body} {resend} + {resendConfirm}
diff --git a/web/web.go b/web/web.go index 305e4f199..b204708b0 100644 --- a/web/web.go +++ b/web/web.go @@ -375,7 +375,10 @@ func verifyEmail(c *api.Context, w http.ResponseWriter, r *http.Request) { } else { user := result.Data.(*model.User) api.FireAndForgetVerifyEmail(user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) - http.Redirect(w, r, "/", http.StatusFound) + + newAddress := strings.Replace(r.URL.String(), "?resend=true", "?resend_success=true", -1) + newAddress = strings.Replace(newAddress, "&resend=true", "&resend_success=true", -1) + http.Redirect(w, r, newAddress, http.StatusFound) return } } -- cgit v1.2.3-1-g7c22 From b4be8eb554d4de1de5b4928a37cb72c34d565487 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 21 Sep 2015 17:03:08 -0700 Subject: Minor changes to how resend status is passed --- web/react/components/email_verify.jsx | 12 +++++++----- web/react/pages/verify.jsx | 1 + web/web.go | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx index 4d4d489bb..8d3f15525 100644 --- a/web/react/components/email_verify.jsx +++ b/web/react/components/email_verify.jsx @@ -10,14 +10,14 @@ export default class EmailVerify extends React.Component { this.state = {}; } handleResend() { - const newAddress = window.location.href.replace('?resend_success=true', '').replace('&resend_success=true', ''); + const newAddress = window.location.href.replace('&resend_success=true', ''); window.location.href = newAddress + '&resend=true'; } render() { var title = ''; var body = ''; var resend = ''; - let resendConfirm = ''; + var resendConfirm = ''; if (this.props.isVerified === 'true') { title = global.window.config.SiteName + ' Email Verified'; body =

Your email has been verified! Click -1) { + if (this.props.resendSuccess) { resendConfirm =


{' Verification email sent.'}

; } } @@ -57,10 +57,12 @@ export default class EmailVerify extends React.Component { EmailVerify.defaultProps = { isVerified: 'false', teamURL: '', - userEmail: '' + userEmail: '', + resendSuccess: 'false' }; EmailVerify.propTypes = { isVerified: React.PropTypes.string, teamURL: React.PropTypes.string, - userEmail: React.PropTypes.string + userEmail: React.PropTypes.string, + resendSuccess: React.PropTypes.string }; diff --git a/web/react/pages/verify.jsx b/web/react/pages/verify.jsx index e48471bbd..16a9846e5 100644 --- a/web/react/pages/verify.jsx +++ b/web/react/pages/verify.jsx @@ -9,6 +9,7 @@ global.window.setupVerifyPage = function setupVerifyPage(props) { isVerified={props.IsVerified} teamURL={props.TeamURL} userEmail={props.UserEmail} + resendSuccess={props.ResendSuccess} />, document.getElementById('verify') ); diff --git a/web/web.go b/web/web.go index b204708b0..9d1946283 100644 --- a/web/web.go +++ b/web/web.go @@ -355,6 +355,7 @@ func getChannel(c *api.Context, w http.ResponseWriter, r *http.Request) { func verifyEmail(c *api.Context, w http.ResponseWriter, r *http.Request) { resend := r.URL.Query().Get("resend") + resendSuccess := r.URL.Query().Get("resend_success") name := r.URL.Query().Get("teamname") email := r.URL.Query().Get("email") hashedId := r.URL.Query().Get("hid") @@ -376,8 +377,7 @@ func verifyEmail(c *api.Context, w http.ResponseWriter, r *http.Request) { user := result.Data.(*model.User) api.FireAndForgetVerifyEmail(user.Id, user.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team)) - newAddress := strings.Replace(r.URL.String(), "?resend=true", "?resend_success=true", -1) - newAddress = strings.Replace(newAddress, "&resend=true", "&resend_success=true", -1) + newAddress := strings.Replace(r.URL.String(), "&resend=true", "&resend_success=true", -1) http.Redirect(w, r, newAddress, http.StatusFound) return } @@ -403,6 +403,7 @@ func verifyEmail(c *api.Context, w http.ResponseWriter, r *http.Request) { page.Props["IsVerified"] = isVerified page.Props["TeamURL"] = c.GetTeamURLFromTeam(team) page.Props["UserEmail"] = email + page.Props["ResendSuccess"] = resendSuccess page.Render(c, w) } -- cgit v1.2.3-1-g7c22 From 38cc1485749c60c32ee9ef8a01da74140588cc3a Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Tue, 22 Sep 2015 11:21:28 +0500 Subject: UI Modifications for multiple tickets --- web/react/components/channel_loader.jsx | 11 ++++++----- web/react/components/new_channel_modal.jsx | 3 ++- web/react/components/sidebar_right_menu.jsx | 4 ++++ web/react/utils/utils.jsx | 3 ++- web/sass-files/sass/partials/_forms.scss | 1 + 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/web/react/components/channel_loader.jsx b/web/react/components/channel_loader.jsx index ce6f60f87..20ea34e15 100644 --- a/web/react/components/channel_loader.jsx +++ b/web/react/components/channel_loader.jsx @@ -90,11 +90,12 @@ export default class ChannelLoader extends React.Component { } /* Setup global mouse events */ - $('body').on('click.userpopover', function popOver(e) { - if ($(e.target).attr('data-toggle') !== 'popover' && - $(e.target).parents('.popover.in').length === 0) { - $('.user-popover').popover('hide'); - } + $('body').on('click', function hidePopover(e) { + $('[data-toggle="popover"]').each(function eachPopover() { + if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) { + $(this).popover('hide'); + } + }); }); $('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) { diff --git a/web/react/components/new_channel_modal.jsx b/web/react/components/new_channel_modal.jsx index 1488a1431..99d5b49e9 100644 --- a/web/react/components/new_channel_modal.jsx +++ b/web/react/components/new_channel_modal.jsx @@ -93,6 +93,7 @@ export default class NewChannelModal extends React.Component { @@ -122,7 +123,7 @@ export default class NewChannelModal extends React.Component { /> {displayNameError}

- {'Channel URL: ' + prettyTeamURL + this.props.channelData.name + ' ('} + {'URL: ' + prettyTeamURL + this.props.channelData.name + ' ('} 24) { + if (teamURL.length > 35) { return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length) + '/'; } + return teamURL + '/'; } diff --git a/web/sass-files/sass/partials/_forms.scss b/web/sass-files/sass/partials/_forms.scss index c8b08f44d..65ea161d4 100644 --- a/web/sass-files/sass/partials/_forms.scss +++ b/web/sass-files/sass/partials/_forms.scss @@ -18,6 +18,7 @@ .input__help { color: #777; margin: 10px 0 0 10px; + word-break: break-word; &.dark { color: #222; } -- cgit v1.2.3-1-g7c22 From 302372cfa0c1f86f78336a5b77e879eac32d27cb Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Tue, 22 Sep 2015 21:01:55 +0500 Subject: Removing click event for channel description popover --- web/react/components/channel_header.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 8d23ec646..b81936b57 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -55,7 +55,7 @@ export default class ChannelHeader extends React.Component { if (!Utils.areStatesEqual(newState, this.state)) { this.setState(newState); } - $('.channel-header__info .description').popover({placement: 'bottom', trigger: 'hover click', html: true, delay: {show: 500, hide: 500}}); + $('.channel-header__info .description').popover({placement: 'bottom', trigger: 'hover', html: true, delay: {show: 500, hide: 500}}); } onSocketChange(msg) { if (msg.action === 'new_user') { -- cgit v1.2.3-1-g7c22 From 09e8874b8ec4c56464b734056175a184196276ec Mon Sep 17 00:00:00 2001 From: hmhealey Date: Tue, 22 Sep 2015 13:27:10 -0400 Subject: Removed click handler from RHS [...] menu --- web/react/components/rhs_comment.jsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index fe31ac381..8d1054e86 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -114,14 +114,7 @@ export default class RhsComment extends React.Component { var ownerOptions; if (isOwner && post.state !== Constants.POST_FAILED && post.state !== Constants.POST_LOADING) { ownerOptions = ( -

+
Date: Tue, 22 Sep 2015 13:53:43 -0400 Subject: Restored changes which remove emojify and switch to our own version --- web/react/components/post_body.jsx | 1 - web/react/components/rhs_comment.jsx | 1 - web/react/components/rhs_root_post.jsx | 1 - web/react/utils/emoticons.jsx | 159 +++++++++++++++++++++++++++++++++ web/react/utils/text_formatting.jsx | 6 ++ web/static/js/emojify.min.js | 4 - web/templates/head.html | 5 -- 7 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 web/react/utils/emoticons.jsx delete mode 100755 web/static/js/emojify.min.js diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx index e0682e997..dbbcdc409 100644 --- a/web/react/components/post_body.jsx +++ b/web/react/components/post_body.jsx @@ -35,7 +35,6 @@ export default class PostBody extends React.Component { parseEmojis() { twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); - global.window.emojify.run(React.findDOMNode(this.refs.message_span)); } componentDidMount() { diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx index fe31ac381..8cc2d309b 100644 --- a/web/react/components/rhs_comment.jsx +++ b/web/react/components/rhs_comment.jsx @@ -56,7 +56,6 @@ export default class RhsComment extends React.Component { } parseEmojis() { twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); - global.window.emojify.run(React.findDOMNode(this.refs.message_holder)); } componentDidMount() { this.parseEmojis(); diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index 2ea697c5b..86620a499 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -20,7 +20,6 @@ export default class RhsRootPost extends React.Component { } parseEmojis() { twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE}); - global.window.emojify.run(React.findDOMNode(this.refs.message_holder)); } componentDidMount() { this.parseEmojis(); diff --git a/web/react/utils/emoticons.jsx b/web/react/utils/emoticons.jsx new file mode 100644 index 000000000..7210201ff --- /dev/null +++ b/web/react/utils/emoticons.jsx @@ -0,0 +1,159 @@ +// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved. +// See License.txt for license information. + +const emoticonPatterns = { + smile: /:-?\)/g, // :) + open_mouth: /:o/gi, // :o + scream: /:-o/gi, // :-o + smirk: /[:;]-?]/g, // :] + grinning: /[:;]-?d/gi, // :D + stuck_out_tongue_closed_eyes: /x-d/gi, // x-d + stuck_out_tongue_winking_eye: /[:;]-?p/gi, // ;p + rage: /:-?[\[@]/g, // :@ + frowning: /:-?\(/g, // :( + sob: /:['’]-?\(|:'\(/g, // :`( + kissing_heart: /:-?\*/g, // :* + wink: /;-?\)/g, // ;) + pensive: /:-?\//g, // :/ + confounded: /:-?s/gi, // :s + flushed: /:-?\|/g, // :| + relaxed: /:-?\$/g, // :$ + mask: /:-x/gi, // :-x + heart: /<3|<3/g, // <3 + broken_heart: /<\/3|</3/g, // `, + originalText: match + }); + + return alias; + } + + return match; + } + + output = output.replace(/:([a-zA-Z0-9_-]+):/g, replaceEmoticonWithToken); + + $.each(emoticonPatterns, (name, pattern) => { + // this might look a bit funny, but since the name isn't contained in the actual match + // like with the named emoticons, we need to add it in manually + output = output.replace(pattern, (match) => replaceEmoticonWithToken(match, name)); + }); + + return output; +} + +function getImagePathForEmoticon(name) { + return `/static/images/emoji/${name}.png`; +} diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx index 4e390f708..be82f7b9c 100644 --- a/web/react/utils/text_formatting.jsx +++ b/web/react/utils/text_formatting.jsx @@ -3,6 +3,7 @@ const Autolinker = require('autolinker'); const Constants = require('./constants.jsx'); +const Emoticons = require('./emoticons.jsx'); const Markdown = require('./markdown.jsx'); const UserStore = require('../stores/user_store.jsx'); const Utils = require('./utils.jsx'); @@ -17,6 +18,7 @@ const markdownRenderer = new Markdown.MattermostMarkdownRenderer(); // - searchTerm - If specified, this word is highlighted in the resulting html. Defaults to nothing. // - mentionHighlight - Specifies whether or not to highlight mentions of the current user. Defaults to true. // - singleline - Specifies whether or not to remove newlines. Defaults to false. +// - emoticons - Enables emoticon parsing. Defaults to true. // - markdown - Enables markdown parsing. Defaults to true. export function formatText(text, options = {}) { if (!('markdown' in options)) { @@ -34,6 +36,10 @@ export function formatText(text, options = {}) { const tokens = new Map(); // replace important words and phrases with tokens + if (!('emoticons' in options) || options.emoticon) { + output = Emoticons.handleEmoticons(output, tokens); + } + output = autolinkUrls(output, tokens, !!options.markdown); output = autolinkAtMentions(output, tokens); output = autolinkHashtags(output, tokens); diff --git a/web/static/js/emojify.min.js b/web/static/js/emojify.min.js deleted file mode 100755 index 4fedf3205..000000000 --- a/web/static/js/emojify.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! emojify.js - v1.0.5 - - * Copyright (c) Hassan Khan 2015 - */ -!function(e,a){"use strict";"function"==typeof define&&define.amd?define([],a):"object"==typeof exports?module.exports=a():e.emojify=a()}(this,function(){"use strict";var e=function(){function e(){var e={named:/:([a-z0-9A-Z_-]+):/,smile:/:-?\)/g,open_mouth:/:o/gi,scream:/:-o/gi,smirk:/[:;]-?]/g,grinning:/[:;]-?d/gi,stuck_out_tongue_closed_eyes:/x-d/gi,stuck_out_tongue_winking_eye:/[:;]-?p/gi,rage:/:-?[\[@]/g,frowning:/:-?\(/g,sob:/:['’]-?\(|:'\(/g,kissing_heart:/:-?\*/g,wink:/;-?\)/g,pensive:/:-?\//g,confounded:/:-?s/gi,flushed:/:-?\|/g,relaxed:/:-?\$/g,mask:/:-x/gi,heart:/<3|<3/g,broken_heart:/<\/3|</3/g,thumbsup:/:\+1:/g,thumbsdown:/:\-1:/g};return d.ignore_emoticons&&(e={named:/:([a-z0-9A-Z_-]+):/,thumbsup:/:\+1:/g,thumbsdown:/:\-1:/g}),Object.keys(e).map(function(a){return[e[a],a]})}function a(){var e=_.map(function(e){var a=e[0],o=a.source||a;return o=o.replace(/(^|[^\[])\^/g,"$1"),"("+o+")"}).join("|");return new RegExp(e,"gi")}function o(e){return" "===e||" "===e||"\r"===e||"\n"===e||""===e||e===String.fromCharCode(160)}function r(e){var a=null;if(e.replacer)a=e.replacer.apply({config:d},[":"+e.emojiName+":",e.emojiName]);else{var o=d.tag_type||h[d.mode];a=e.win.document.createElement(o),"img"!==o?a.setAttribute("class","emoji emoji-"+e.emojiName):(a.setAttribute("align","absmiddle"),a.setAttribute("alt",":"+e.emojiName+":"),a.setAttribute("class","emoji"),a.setAttribute("src",d.img_dir+"/"+e.emojiName+".png")),a.setAttribute("title",":"+e.emojiName+":")}e.node.splitText(e.match.index),e.node.nextSibling.nodeValue=e.node.nextSibling.nodeValue.substr(e.match[0].length,e.node.nextSibling.nodeValue.length),a.appendChild(e.node.splitText(e.match.index)),e.node.parentNode.insertBefore(a,e.node.nextSibling)}function t(e){if(e[1]&&e[2]){var a=e[2];if(m[a])return a}else for(var o=3;o":":"+a+":"}function n(){this.lastEmojiTerminatedAt=-1}function s(o,r){if(!o)return o;r||(r=i),_=e(),c=a();var t=new n;return o.replace(c,function(){var e=Array.prototype.slice.call(arguments,0,-2),a=arguments[arguments.length-2],o=arguments[arguments.length-1],i=t.validate(e,a,o);return i?r.apply({config:d},[arguments[0],i]):arguments[0]})}function l(o,i){"undefined"==typeof o&&(o=d.only_crawl_id?document.getElementById(d.only_crawl_id):document.body);var s=o.ownerDocument,l=s.defaultView||s.parentWindow,u=function(e,a){var o;if(e.hasChildNodes())for(o=e.firstChild;o;)a(o)&&u(o,a),o=o.nextSibling},g=function(e){for(var a,o=[],s=new n;null!==(a=c.exec(e.data));)s.validate(a,a.index,a.input)&&o.push(a);for(var _=o.length;_-->0;){var u=t(o[_]);r({node:e,match:o[_],emojiName:u,replacer:i,win:l})}};_=e(),c=a();var m=[],h=new RegExp(d.blacklist.elements.join("|"),"i"),p=new RegExp(d.blacklist.classes.join("|"),"i");if("undefined"!=typeof l.document.createTreeWalker)for(var b,f=l.document.createTreeWalker(o,l.NodeFilter.SHOW_TEXT|l.NodeFilter.SHOW_ELEMENT,function(e){return 1!==e.nodeType?l.NodeFilter.FILTER_ACCEPT:e.tagName.match(h)||"svg"===e.tagName||e.className.match(p)?l.NodeFilter.FILTER_REJECT:l.NodeFilter.FILTER_SKIP},!1);null!==(b=f.nextNode());)m.push(b);else u(o,function(e){return"undefined"!=typeof e.tagName&&e.tagName.match(h)||"undefined"!=typeof e.className&&e.className.match(p)?!1:1===e.nodeType?!0:(m.push(e),!0)});m.forEach(g)}var _,c,u="+1,-1,100,1234,8ball,a,ab,abc,abcd,accept,aerial_tramway,airplane,alarm_clock,alien,ambulance,anchor,angel,anger,angry,anguished,ant,apple,aquarius,aries,arrow_backward,arrow_double_down,arrow_double_up,arrow_down,arrow_down_small,arrow_forward,arrow_heading_down,arrow_heading_up,arrow_left,arrow_lower_left,arrow_lower_right,arrow_right,arrow_right_hook,arrow_up,arrow_up_down,arrow_up_small,arrow_upper_left,arrow_upper_right,arrows_clockwise,arrows_counterclockwise,art,articulated_lorry,astonished,atm,b,baby,baby_bottle,baby_chick,baby_symbol,back,baggage_claim,balloon,ballot_box_with_check,bamboo,banana,bangbang,bank,bar_chart,barber,baseball,basketball,bath,bathtub,battery,bear,bee,beer,beers,beetle,beginner,bell,bento,bicyclist,bike,bikini,bird,birthday,black_circle,black_joker,black_medium_small_square,black_medium_square,black_nib,black_small_square,black_square,black_square_button,blossom,blowfish,blue_book,blue_car,blue_heart,blush,boar,boat,bomb,book,bookmark,bookmark_tabs,books,boom,boot,bouquet,bow,bowling,bowtie,boy,bread,bride_with_veil,bridge_at_night,briefcase,broken_heart,bug,bulb,bullettrain_front,bullettrain_side,bus,busstop,bust_in_silhouette,busts_in_silhouette,cactus,cake,calendar,calling,camel,camera,cancer,candy,capital_abcd,capricorn,car,card_index,carousel_horse,cat,cat2,cd,chart,chart_with_downwards_trend,chart_with_upwards_trend,checkered_flag,cherries,cherry_blossom,chestnut,chicken,children_crossing,chocolate_bar,christmas_tree,church,cinema,circus_tent,city_sunrise,city_sunset,cl,clap,clapper,clipboard,clock1,clock10,clock1030,clock11,clock1130,clock12,clock1230,clock130,clock2,clock230,clock3,clock330,clock4,clock430,clock5,clock530,clock6,clock630,clock7,clock730,clock8,clock830,clock9,clock930,closed_book,closed_lock_with_key,closed_umbrella,cloud,clubs,cn,cocktail,coffee,cold_sweat,collision,computer,confetti_ball,confounded,confused,congratulations,construction,construction_worker,convenience_store,cookie,cool,cop,copyright,corn,couple,couple_with_heart,couplekiss,cow,cow2,credit_card,crescent_moon,crocodile,crossed_flags,crown,cry,crying_cat_face,crystal_ball,cupid,curly_loop,currency_exchange,curry,custard,customs,cyclone,dancer,dancers,dango,dart,dash,date,de,deciduous_tree,department_store,diamond_shape_with_a_dot_inside,diamonds,disappointed,disappointed_relieved,dizzy,dizzy_face,do_not_litter,dog,dog2,dollar,dolls,dolphin,donut,door,doughnut,dragon,dragon_face,dress,dromedary_camel,droplet,dvd,e-mail,ear,ear_of_rice,earth_africa,earth_americas,earth_asia,egg,eggplant,eight,eight_pointed_black_star,eight_spoked_asterisk,electric_plug,elephant,email,end,envelope,es,euro,european_castle,european_post_office,evergreen_tree,exclamation,expressionless,eyeglasses,eyes,facepunch,factory,fallen_leaf,family,fast_forward,fax,fearful,feelsgood,feet,ferris_wheel,file_folder,finnadie,fire,fire_engine,fireworks,first_quarter_moon,first_quarter_moon_with_face,fish,fish_cake,fishing_pole_and_fish,fist,five,flags,flashlight,floppy_disk,flower_playing_cards,flushed,foggy,football,fork_and_knife,fountain,four,four_leaf_clover,fr,free,fried_shrimp,fries,frog,frowning,fu,fuelpump,full_moon,full_moon_with_face,game_die,gb,gem,gemini,ghost,gift,gift_heart,girl,globe_with_meridians,goat,goberserk,godmode,golf,grapes,green_apple,green_book,green_heart,grey_exclamation,grey_question,grimacing,grin,grinning,guardsman,guitar,gun,haircut,hamburger,hammer,hamster,hand,handbag,hankey,hash,hatched_chick,hatching_chick,headphones,hear_no_evil,heart,heart_decoration,heart_eyes,heart_eyes_cat,heartbeat,heartpulse,hearts,heavy_check_mark,heavy_division_sign,heavy_dollar_sign,heavy_exclamation_mark,heavy_minus_sign,heavy_multiplication_x,heavy_plus_sign,helicopter,herb,hibiscus,high_brightness,high_heel,hocho,honey_pot,honeybee,horse,horse_racing,hospital,hotel,hotsprings,hourglass,hourglass_flowing_sand,house,house_with_garden,hurtrealbad,hushed,ice_cream,icecream,id,ideograph_advantage,imp,inbox_tray,incoming_envelope,information_desk_person,information_source,innocent,interrobang,iphone,it,izakaya_lantern,jack_o_lantern,japan,japanese_castle,japanese_goblin,japanese_ogre,jeans,joy,joy_cat,jp,key,keycap_ten,kimono,kiss,kissing,kissing_cat,kissing_closed_eyes,kissing_face,kissing_heart,kissing_smiling_eyes,koala,koko,kr,large_blue_circle,large_blue_diamond,large_orange_diamond,last_quarter_moon,last_quarter_moon_with_face,laughing,leaves,ledger,left_luggage,left_right_arrow,leftwards_arrow_with_hook,lemon,leo,leopard,libra,light_rail,link,lips,lipstick,lock,lock_with_ink_pen,lollipop,loop,loudspeaker,love_hotel,love_letter,low_brightness,m,mag,mag_right,mahjong,mailbox,mailbox_closed,mailbox_with_mail,mailbox_with_no_mail,man,man_with_gua_pi_mao,man_with_turban,mans_shoe,maple_leaf,mask,massage,meat_on_bone,mega,melon,memo,mens,metal,metro,microphone,microscope,milky_way,minibus,minidisc,mobile_phone_off,money_with_wings,moneybag,monkey,monkey_face,monorail,mortar_board,mount_fuji,mountain_bicyclist,mountain_cableway,mountain_railway,mouse,mouse2,movie_camera,moyai,muscle,mushroom,musical_keyboard,musical_note,musical_score,mute,nail_care,name_badge,neckbeard,necktie,negative_squared_cross_mark,neutral_face,new,new_moon,new_moon_with_face,newspaper,ng,nine,no_bell,no_bicycles,no_entry,no_entry_sign,no_good,no_mobile_phones,no_mouth,no_pedestrians,no_smoking,non-potable_water,nose,notebook,notebook_with_decorative_cover,notes,nut_and_bolt,o,o2,ocean,octocat,octopus,oden,office,ok,ok_hand,ok_woman,older_man,older_woman,on,oncoming_automobile,oncoming_bus,oncoming_police_car,oncoming_taxi,one,open_file_folder,open_hands,open_mouth,ophiuchus,orange_book,outbox_tray,ox,package,page_facing_up,page_with_curl,pager,palm_tree,panda_face,paperclip,parking,part_alternation_mark,partly_sunny,passport_control,paw_prints,peach,pear,pencil,pencil2,penguin,pensive,performing_arts,persevere,person_frowning,person_with_blond_hair,person_with_pouting_face,phone,pig,pig2,pig_nose,pill,pineapple,pisces,pizza,plus1,point_down,point_left,point_right,point_up,point_up_2,police_car,poodle,poop,post_office,postal_horn,postbox,potable_water,pouch,poultry_leg,pound,pouting_cat,pray,princess,punch,purple_heart,purse,pushpin,put_litter_in_its_place,question,rabbit,rabbit2,racehorse,radio,radio_button,rage,rage1,rage2,rage3,rage4,railway_car,rainbow,raised_hand,raised_hands,raising_hand,ram,ramen,rat,recycle,red_car,red_circle,registered,relaxed,relieved,repeat,repeat_one,restroom,revolving_hearts,rewind,ribbon,rice,rice_ball,rice_cracker,rice_scene,ring,rocket,roller_coaster,rooster,rose,rotating_light,round_pushpin,rowboat,ru,rugby_football,runner,running,running_shirt_with_sash,sa,sagittarius,sailboat,sake,sandal,santa,satellite,satisfied,saxophone,school,school_satchel,scissors,scorpius,scream,scream_cat,scroll,seat,secret,see_no_evil,seedling,seven,shaved_ice,sheep,shell,ship,shipit,shirt,shit,shoe,shower,signal_strength,six,six_pointed_star,ski,skull,sleeping,sleepy,slot_machine,small_blue_diamond,small_orange_diamond,small_red_triangle,small_red_triangle_down,smile,smile_cat,smiley,smiley_cat,smiling_imp,smirk,smirk_cat,smoking,snail,snake,snowboarder,snowflake,snowman,sob,soccer,soon,sos,sound,space_invader,spades,spaghetti,sparkle,sparkler,sparkles,sparkling_heart,speak_no_evil,speaker,speech_balloon,speedboat,squirrel,star,star2,stars,station,statue_of_liberty,steam_locomotive,stew,straight_ruler,strawberry,stuck_out_tongue,stuck_out_tongue_closed_eyes,stuck_out_tongue_winking_eye,sun_with_face,sunflower,sunglasses,sunny,sunrise,sunrise_over_mountains,surfer,sushi,suspect,suspension_railway,sweat,sweat_drops,sweat_smile,sweet_potato,swimmer,symbols,syringe,tada,tanabata_tree,tangerine,taurus,taxi,tea,telephone,telephone_receiver,telescope,tennis,tent,thought_balloon,three,thumbsdown,thumbsup,ticket,tiger,tiger2,tired_face,tm,toilet,tokyo_tower,tomato,tongue,top,tophat,tractor,traffic_light,train,train2,tram,triangular_flag_on_post,triangular_ruler,trident,triumph,trolleybus,trollface,trophy,tropical_drink,tropical_fish,truck,trumpet,tshirt,tulip,turtle,tv,twisted_rightwards_arrows,two,two_hearts,two_men_holding_hands,two_women_holding_hands,u5272,u5408,u55b6,u6307,u6708,u6709,u6e80,u7121,u7533,u7981,u7a7a,uk,umbrella,unamused,underage,unlock,up,us,v,vertical_traffic_light,vhs,vibration_mode,video_camera,video_game,violin,virgo,volcano,vs,walking,waning_crescent_moon,waning_gibbous_moon,warning,watch,water_buffalo,watermelon,wave,wavy_dash,waxing_crescent_moon,waxing_gibbous_moon,wc,weary,wedding,whale,whale2,wheelchair,white_check_mark,white_circle,white_flower,white_large_square,white_medium_small_square,white_medium_square,white_small_square,white_square_button,wind_chime,wine_glass,wink,wolf,woman,womans_clothes,womans_hat,womens,worried,wrench,x,yellow_heart,yen,yum,zap,zero,zzz",g=u.split(/,/),m=g.reduce(function(e,a){return e[a]=!0,e},{}),d={blacklist:{ids:[],classes:["no-emojify"],elements:["script","textarea","a","pre","code"]},tag_type:null,only_crawl_id:null,img_dir:"images/emoji",ignore_emoticons:!1,mode:"img"},h={img:"img",sprite:"span","data-uri":"span"};return n.prototype={validate:function(e,a,r){function i(){return n.lastEmojiTerminatedAt=_+a,s}var n=this,s=t(e);if(s){var l=e[0],_=l.length;if(0===a)return i();if(r.length===l.length+a)return i();var c=this.lastEmojiTerminatedAt===a;if(c)return i();if(o(r.charAt(a-1)))return i();var u=o(r.charAt(l.length+a));return u&&c?i():void 0}}},{defaultConfig:d,emojiNames:g,setConfig:function(e){Object.keys(d).forEach(function(a){a in e&&(d[a]=e[a])})},replace:s,run:l}}();return e}); \ No newline at end of file diff --git a/web/templates/head.html b/web/templates/head.html index af5c86bba..a3ac930e9 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -40,11 +40,6 @@ - - - + -- cgit v1.2.3-1-g7c22 From f7a32fa38a5c9f33d7fbb3d73d240626211173cc Mon Sep 17 00:00:00 2001 From: Chengwei Yang Date: Wed, 23 Sep 2015 22:37:40 +0800 Subject: PLT-126: Change 'Private Messages' to 'Direct Messages' Signed-off-by: Chengwei Yang --- api/post.go | 2 +- web/react/components/more_direct_channels.jsx | 2 +- web/react/components/post_list.jsx | 6 +++--- web/react/components/rhs_root_post.jsx | 2 +- web/react/components/search_results_item.jsx | 2 +- web/react/components/sidebar.jsx | 2 +- web/react/components/user_settings/user_settings_notifications.jsx | 6 +++--- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/api/post.go b/api/post.go index 21bc35b97..bbbc93115 100644 --- a/api/post.go +++ b/api/post.go @@ -230,7 +230,7 @@ func fireAndForgetNotifications(post *model.Post, teamId, siteURL string) { channel = result.Data.(*model.Channel) if channel.Type == model.CHANNEL_DIRECT { bodyText = "You have one new message." - subjectText = "New Private Message" + subjectText = "New Direct Message" } else { bodyText = "You have one new mention." subjectText = "New Mention" diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx index f27b09ecc..b7bce9b34 100644 --- a/web/react/components/more_direct_channels.jsx +++ b/web/react/components/more_direct_channels.jsx @@ -114,7 +114,7 @@ export default class MoreDirectChannels extends React.Component { Close -

More Private Messages

+

More Direct Messages

    diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx index 703e548fb..218922b67 100644 --- a/web/react/components/post_list.jsx +++ b/web/react/components/post_list.jsx @@ -326,8 +326,8 @@ export default class PostList extends React.Component {

- {'This is the start of your private message history with ' + teammateName + '.'}
- {'Private messages and files shared here are not shown to people outside this area.'} + {'This is the start of your direct message history with ' + teammateName + '.'}
+ {'Direct messages and files shared here are not shown to people outside this area.'}

-

{'This is the start of your private message history with this teammate. Private messages and files shared here are not shown to people outside this area.'}

+

{'This is the start of your direct message history with this teammate. Direct messages and files shared here are not shown to people outside this area.'}

); } diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx index 86620a499..e661bdce1 100644 --- a/web/react/components/rhs_root_post.jsx +++ b/web/react/components/rhs_root_post.jsx @@ -53,7 +53,7 @@ export default class RhsRootPost extends React.Component { var channelName; if (channel) { if (channel.type === 'D') { - channelName = 'Private Message'; + channelName = 'Direct Message'; } else { channelName = channel.display_name; } diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index 0e951f5c6..32b521560 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -64,7 +64,7 @@ export default class SearchResultsItem extends React.Component { if (channel) { channelName = channel.display_name; if (channel.type === 'D') { - channelName = 'Private Message'; + channelName = 'Direct Message'; } } diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx index 87007edcc..14664ed4d 100644 --- a/web/react/components/sidebar.jsx +++ b/web/react/components/sidebar.jsx @@ -566,7 +566,7 @@ export default class Sidebar extends React.Component { {privateChannelItems} diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx index fde4970ce..8d364cde7 100644 --- a/web/react/components/user_settings/user_settings_notifications.jsx +++ b/web/react/components/user_settings/user_settings_notifications.jsx @@ -241,7 +241,7 @@ export default class NotificationsTab extends React.Component { checked={notifyActive[1]} onChange={this.handleNotifyRadio.bind(this, 'mention')} > - Only for mentions and private messages + Only for mentions and direct messages
@@ -277,7 +277,7 @@ export default class NotificationsTab extends React.Component { } else { let describe = ''; if (this.state.notifyLevel === 'mention') { - describe = 'Only for mentions and private messages'; + describe = 'Only for mentions and direct messages'; } else if (this.state.notifyLevel === 'none') { describe = 'Never'; } else { @@ -414,7 +414,7 @@ export default class NotificationsTab extends React.Component {
-

{'Email notifications are sent for mentions and private messages after you have been away from ' + global.window.config.SiteName + ' for 5 minutes.'}
+

{'Email notifications are sent for mentions and direct messages after you have been away from ' + global.window.config.SiteName + ' for 5 minutes.'}
); -- cgit v1.2.3-1-g7c22 From 845229d9836412c2592fdcd9da0e7b1b9fc76a15 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 23 Sep 2015 12:25:01 -0400 Subject: Fix post not rendering properly in some cases. --- web/react/components/post.jsx | 51 ++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index d3c6befd0..9127f00de 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -51,7 +51,7 @@ export default class Post extends React.Component { var post = this.props.post; client.createPost(post, post.channel_id, - function success(data) { + (data) => { AsyncClient.getPosts(); var channel = ChannelStore.get(post.channel_id); @@ -65,11 +65,11 @@ export default class Post extends React.Component { post: data }); }, - function error() { + () => { post.state = Constants.POST_FAILED; PostStore.updatePendingPost(post); this.forceUpdate(); - }.bind(this) + } ); post.state = Constants.POST_LOADING; @@ -81,31 +81,52 @@ export default class Post extends React.Component { return true; } - return false; - } - render() { - var post = this.props.post; - var parentPost = this.props.parentPost; - var posts = this.props.posts; + if (nextProps.sameRoot !== this.props.sameRoot) { + return true; + } - var type = 'Post'; - if (post.root_id && post.root_id.length > 0) { - type = 'Comment'; + if (nextProps.sameUser !== this.props.sameUser) { + return true; + } + + if (this.getCommentCount(nextProps) !== this.getCommentCount(this.props)) { + return true; } - var commentCount = 0; - var commentRootId; + return false; + } + getCommentCount(props) { + const post = props.post; + const parentPost = props.parentPost; + const posts = props.posts; + + let commentCount = 0; + let commentRootId; if (parentPost) { commentRootId = post.root_id; } else { commentRootId = post.id; } - for (var postId in posts) { + for (let postId in posts) { if (posts[postId].root_id === commentRootId) { commentCount += 1; } } + return commentCount; + } + render() { + var post = this.props.post; + var parentPost = this.props.parentPost; + var posts = this.props.posts; + + var type = 'Post'; + if (post.root_id && post.root_id.length > 0) { + type = 'Comment'; + } + + const commentCount = this.getCommentCount(this.props); + var rootUser; if (this.props.sameRoot) { rootUser = 'same--root'; -- cgit v1.2.3-1-g7c22 From 47aab71e6b62c01ae66389aec39bec7fb2a0435f Mon Sep 17 00:00:00 2001 From: Asaad Mahmood Date: Wed, 23 Sep 2015 23:37:36 +0500 Subject: Markdown UI improvements with small description height fix --- web/sass-files/sass/partials/_headers.scss | 1 + web/sass-files/sass/partials/_markdown.scss | 28 ++++++++++++++++++++++++++++ web/sass-files/sass/styles.scss | 1 + 3 files changed, 30 insertions(+) create mode 100644 web/sass-files/sass/partials/_markdown.scss diff --git a/web/sass-files/sass/partials/_headers.scss b/web/sass-files/sass/partials/_headers.scss index 702f0fd60..eaa31c8ed 100644 --- a/web/sass-files/sass/partials/_headers.scss +++ b/web/sass-files/sass/partials/_headers.scss @@ -39,6 +39,7 @@ text-overflow: ellipsis; color: #888; margin-top: 2px; + max-height: 45px; } &.popover { white-space: normal; diff --git a/web/sass-files/sass/partials/_markdown.scss b/web/sass-files/sass/partials/_markdown.scss new file mode 100644 index 000000000..c09e9d7b4 --- /dev/null +++ b/web/sass-files/sass/partials/_markdown.scss @@ -0,0 +1,28 @@ +.markdown__heading { + font-weight: bold; +} +.markdown__table { + background: #fff; + margin: 5px 0 10px; + th, td { + padding: 6px 13px; + border: 1px solid #ddd; + } + tbody tr { + background: #fff; + &:nth-child(2n) { + background-color: #f8f8f8; + } + } +} +pre { + border: none; + background-color: #f7f7f7; + margin: 5px 0; + .current--user & { + background: #fff; + } + code { + color: #c7254e; + } +} \ No newline at end of file diff --git a/web/sass-files/sass/styles.scss b/web/sass-files/sass/styles.scss index de1db57e8..be6641870 100644 --- a/web/sass-files/sass/styles.scss +++ b/web/sass-files/sass/styles.scss @@ -36,6 +36,7 @@ @import "partials/error-bar"; @import "partials/loading"; @import "partials/get-link"; +@import "partials/markdown"; // Responsive Css @import "partials/responsive"; -- cgit v1.2.3-1-g7c22 From e79e66c0a41dd4aaf0bf2873689120253c9339a7 Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Wed, 23 Sep 2015 15:29:39 -0400 Subject: Fix theme images 404ing. --- web/react/components/user_settings/premade_theme_chooser.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/react/components/user_settings/premade_theme_chooser.jsx b/web/react/components/user_settings/premade_theme_chooser.jsx index e36503053..e6aa2f5b9 100644 --- a/web/react/components/user_settings/premade_theme_chooser.jsx +++ b/web/react/components/user_settings/premade_theme_chooser.jsx @@ -31,7 +31,7 @@ export default class PremadeThemeChooser extends React.Component { -- cgit v1.2.3-1-g7c22 From ccf2e6e4e74fc249a094c2c27de675644f1065cb Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 23 Sep 2015 13:47:10 -0700 Subject: Changing image settings to file settings --- api/export.go | 6 +- api/file.go | 64 +++++++++--------- api/file_benchmark_test.go | 2 +- api/file_test.go | 56 ++++++++-------- api/user.go | 12 ++-- api/user_test.go | 26 ++++---- config/config.json | 4 +- docker/dev/config_docker.json | 2 +- docker/local/config_docker.json | 2 +- model/config.go | 4 +- utils/config.go | 6 +- .../components/admin_console/admin_controller.jsx | 4 +- .../components/admin_console/admin_sidebar.jsx | 2 +- .../components/admin_console/image_settings.jsx | 76 +++++++++++----------- web/react/components/signup_team.jsx | 2 +- 15 files changed, 134 insertions(+), 134 deletions(-) diff --git a/api/export.go b/api/export.go index 6d7698282..73142a0e4 100644 --- a/api/export.go +++ b/api/export.go @@ -278,11 +278,11 @@ func copyDirToExportWriter(writer ExportWriter, inPath string, outPath string) * } func ExportLocalStorage(writer ExportWriter, options *ExportOptions, teamId string) *model.AppError { - teamDir := utils.Cfg.ImageSettings.Directory + "teams/" + teamId + teamDir := utils.Cfg.FileSettings.Directory + "teams/" + teamId - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { return model.NewAppError("ExportLocalStorage", "S3 is not supported for local storage export.", "") - } else if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_LOCAL { + } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { if err := copyDirToExportWriter(writer, teamDir, EXPORT_LOCAL_STORAGE_FOLDER); err != nil { return err } diff --git a/api/file.go b/api/file.go index acb18a7d4..694fc734c 100644 --- a/api/file.go +++ b/api/file.go @@ -69,7 +69,7 @@ func InitFile(r *mux.Router) { } func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { c.Err = model.NewAppError("uploadFile", "Unable to upload file. Image storage is not configured.", "") c.Err.StatusCode = http.StatusNotImplemented return @@ -217,8 +217,8 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch // Create thumbnail go func() { - thumbWidth := float64(utils.Cfg.ImageSettings.ThumbnailWidth) - thumbHeight := float64(utils.Cfg.ImageSettings.ThumbnailHeight) + thumbWidth := float64(utils.Cfg.FileSettings.ThumbnailWidth) + thumbHeight := float64(utils.Cfg.FileSettings.ThumbnailHeight) imgWidth := float64(width) imgHeight := float64(height) @@ -226,9 +226,9 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch if imgHeight < thumbHeight && imgWidth < thumbWidth { thumbnail = img } else if imgHeight/imgWidth < thumbHeight/thumbWidth { - thumbnail = resize.Resize(0, utils.Cfg.ImageSettings.ThumbnailHeight, img, resize.Lanczos3) + thumbnail = resize.Resize(0, utils.Cfg.FileSettings.ThumbnailHeight, img, resize.Lanczos3) } else { - thumbnail = resize.Resize(utils.Cfg.ImageSettings.ThumbnailWidth, 0, img, resize.Lanczos3) + thumbnail = resize.Resize(utils.Cfg.FileSettings.ThumbnailWidth, 0, img, resize.Lanczos3) } buf := new(bytes.Buffer) @@ -247,8 +247,8 @@ func fireAndForgetHandleImages(filenames []string, fileData [][]byte, teamId, ch // Create preview go func() { var preview image.Image - if width > int(utils.Cfg.ImageSettings.PreviewWidth) { - preview = resize.Resize(utils.Cfg.ImageSettings.PreviewWidth, utils.Cfg.ImageSettings.PreviewHeight, img, resize.Lanczos3) + if width > int(utils.Cfg.FileSettings.PreviewWidth) { + preview = resize.Resize(utils.Cfg.FileSettings.PreviewWidth, utils.Cfg.FileSettings.PreviewHeight, img, resize.Lanczos3) } else { preview = img } @@ -294,7 +294,7 @@ type ImageGetResult struct { } func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) { - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { c.Err = model.NewAppError("uploadFile", "Unable to get file info. Image storage is not configured.", "") c.Err.StatusCode = http.StatusNotImplemented return @@ -357,7 +357,7 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) { } func getFile(c *Context, w http.ResponseWriter, r *http.Request) { - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { c.Err = model.NewAppError("uploadFile", "Unable to get file. Image storage is not configured.", "") c.Err.StatusCode = http.StatusNotImplemented return @@ -400,7 +400,7 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) { asyncGetFile(path, fileData) if len(hash) > 0 && len(data) > 0 && len(teamId) == 26 { - if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt)) { + if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt)) { c.Err = model.NewAppError("getFile", "The public link does not appear to be valid", "") return } @@ -442,13 +442,13 @@ func asyncGetFile(path string, fileData chan []byte) { } func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) { - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { c.Err = model.NewAppError("uploadFile", "Unable to get link. Image storage is not configured.", "") c.Err.StatusCode = http.StatusNotImplemented return } - if !utils.Cfg.ImageSettings.EnablePublicLink { + if !utils.Cfg.FileSettings.EnablePublicLink { c.Err = model.NewAppError("getPublicLink", "Public links have been disabled", "") c.Err.StatusCode = http.StatusForbidden } @@ -478,7 +478,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) { newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) data := model.MapToJson(newProps) - hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt)) + hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt)) url := fmt.Sprintf("%s/api/v1/files/get/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL(), channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.Session.TeamId) @@ -511,13 +511,13 @@ func getExport(c *Context, w http.ResponseWriter, r *http.Request) { func writeFile(f []byte, path string) *model.AppError { - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) ext := filepath.Ext(path) @@ -534,12 +534,12 @@ func writeFile(f []byte, path string) *model.AppError { if err != nil { return model.NewAppError("writeFile", "Encountered an error writing to S3", err.Error()) } - } else if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_LOCAL { - if err := os.MkdirAll(filepath.Dir(utils.Cfg.ImageSettings.Directory+path), 0774); err != nil { + } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { + if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil { return model.NewAppError("writeFile", "Encountered an error creating the directory for the new file", err.Error()) } - if err := ioutil.WriteFile(utils.Cfg.ImageSettings.Directory+path, f, 0644); err != nil { + if err := ioutil.WriteFile(utils.Cfg.FileSettings.Directory+path, f, 0644); err != nil { return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error()) } } else { @@ -551,13 +551,13 @@ func writeFile(f []byte, path string) *model.AppError { func readFile(path string) ([]byte, *model.AppError) { - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) // try to get the file from S3 with some basic retry logic tries := 0 @@ -573,8 +573,8 @@ func readFile(path string) ([]byte, *model.AppError) { } time.Sleep(3000 * time.Millisecond) } - } else if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_LOCAL { - if f, err := ioutil.ReadFile(utils.Cfg.ImageSettings.Directory + path); err != nil { + } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { + if f, err := ioutil.ReadFile(utils.Cfg.FileSettings.Directory + path); err != nil { return nil, model.NewAppError("readFile", "Encountered an error reading from local server storage", err.Error()) } else { return f, nil @@ -585,14 +585,14 @@ func readFile(path string) ([]byte, *model.AppError) { } func openFileWriteStream(path string) (io.Writer, *model.AppError) { - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { return nil, model.NewAppError("openFileWriteStream", "S3 is not supported.", "") - } else if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_LOCAL { - if err := os.MkdirAll(filepath.Dir(utils.Cfg.ImageSettings.Directory+path), 0774); err != nil { + } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { + if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil { return nil, model.NewAppError("openFileWriteStream", "Encountered an error creating the directory for the new file", err.Error()) } - if fileHandle, err := os.Create(utils.Cfg.ImageSettings.Directory + path); err != nil { + if fileHandle, err := os.Create(utils.Cfg.FileSettings.Directory + path); err != nil { return nil, model.NewAppError("openFileWriteStream", "Encountered an error writing to local server storage", err.Error()) } else { fileHandle.Chmod(0644) diff --git a/api/file_benchmark_test.go b/api/file_benchmark_test.go index f7d5de1d9..47f8bff43 100644 --- a/api/file_benchmark_test.go +++ b/api/file_benchmark_test.go @@ -38,7 +38,7 @@ func BenchmarkGetFile(b *testing.B) { newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) data := model.MapToJson(newProps) - hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt)) + hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt)) // wait a bit for files to ready time.Sleep(5 * time.Second) diff --git a/api/file_test.go b/api/file_test.go index 072a3fab1..657c08131 100644 --- a/api/file_test.go +++ b/api/file_test.go @@ -68,7 +68,7 @@ func TestUploadFile(t *testing.T) { } resp, appErr := Client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType()) - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { if appErr != nil { t.Fatal(appErr) } @@ -81,11 +81,11 @@ func TestUploadFile(t *testing.T) { fileId := strings.Split(filename, ".")[0] var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) // wait a bit for files to ready time.Sleep(5 * time.Second) @@ -104,7 +104,7 @@ func TestUploadFile(t *testing.T) { if err != nil { t.Fatal(err) } - } else if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_LOCAL { + } else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL { filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/") filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1] if strings.Contains(filename, "../") { @@ -115,17 +115,17 @@ func TestUploadFile(t *testing.T) { // wait a bit for files to ready time.Sleep(5 * time.Second) - path := utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename + path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } @@ -151,7 +151,7 @@ func TestGetFile(t *testing.T) { channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) - if utils.Cfg.ImageSettings.DriverName != "" { + if utils.Cfg.FileSettings.DriverName != "" { body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -222,7 +222,7 @@ func TestGetFile(t *testing.T) { newProps["time"] = fmt.Sprintf("%v", model.GetMillis()) data := model.MapToJson(newProps) - hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.ImageSettings.PublicLinkSalt)) + hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt)) Client.LoginByEmail(team2.Name, user2.Email, "pwd") @@ -262,13 +262,13 @@ func TestGetFile(t *testing.T) { t.Fatal("Should have errored - user not logged in and link not public") } - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/") filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1] @@ -293,17 +293,17 @@ func TestGetFile(t *testing.T) { filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1] fileId := strings.Split(filename, ".")[0] - path := utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename + path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } @@ -334,7 +334,7 @@ func TestGetPublicLink(t *testing.T) { channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id} channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel) - if utils.Cfg.ImageSettings.DriverName != "" { + if utils.Cfg.FileSettings.DriverName != "" { body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -410,14 +410,14 @@ func TestGetPublicLink(t *testing.T) { t.Fatal("should have errored, user not member of channel") } - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { // perform clean-up on s3 var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) filenames := strings.Split(resp.Data.(*model.FileUploadResponse).Filenames[0], "/") filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1] @@ -442,17 +442,17 @@ func TestGetPublicLink(t *testing.T) { filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1] fileId := strings.Split(filename, ".")[0] - path := utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename + path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } - path = utils.Cfg.ImageSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" + path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } diff --git a/api/user.go b/api/user.go index 5bb65e2ed..40410cc5b 100644 --- a/api/user.go +++ b/api/user.go @@ -646,7 +646,7 @@ func createProfileImage(username string, userId string) ([]byte, *model.AppError initial := string(strings.ToUpper(username)[0]) - fontBytes, err := ioutil.ReadFile(utils.FindDir("web/static/fonts") + utils.Cfg.ImageSettings.InitialFont) + fontBytes, err := ioutil.ReadFile(utils.FindDir("web/static/fonts") + utils.Cfg.FileSettings.InitialFont) if err != nil { return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error()) } @@ -655,8 +655,8 @@ func createProfileImage(username string, userId string) ([]byte, *model.AppError return nil, model.NewAppError("createProfileImage", "Could not create default profile image font", err.Error()) } - width := int(utils.Cfg.ImageSettings.ProfileWidth) - height := int(utils.Cfg.ImageSettings.ProfileHeight) + width := int(utils.Cfg.FileSettings.ProfileWidth) + height := int(utils.Cfg.FileSettings.ProfileHeight) color := colors[int64(seed)%int64(len(colors))] dstImg := image.NewRGBA(image.Rect(0, 0, width, height)) srcImg := image.White @@ -695,7 +695,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { } else { var img []byte - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { var err *model.AppError if img, err = createProfileImage(result.Data.(*model.User).Username, id); err != nil { c.Err = err @@ -732,7 +732,7 @@ func getProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { } func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { - if len(utils.Cfg.ImageSettings.DriverName) == 0 { + if len(utils.Cfg.FileSettings.DriverName) == 0 { c.Err = model.NewAppError("uploadProfileImage", "Unable to upload file. Image storage is not configured.", "") c.Err.StatusCode = http.StatusNotImplemented return @@ -775,7 +775,7 @@ func uploadProfileImage(c *Context, w http.ResponseWriter, r *http.Request) { } // Scale profile image - img = resize.Resize(utils.Cfg.ImageSettings.ProfileWidth, utils.Cfg.ImageSettings.ProfileHeight, img, resize.Lanczos3) + img = resize.Resize(utils.Cfg.FileSettings.ProfileWidth, utils.Cfg.FileSettings.ProfileHeight, img, resize.Lanczos3) buf := new(bytes.Buffer) err = png.Encode(buf, img) diff --git a/api/user_test.go b/api/user_test.go index 34eefce59..669da4d20 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -352,19 +352,19 @@ func TestUserCreateImage(t *testing.T) { Client.DoApiGet("/users/"+user.Id+"/image", "", "") - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) if err := bucket.Del("teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"); err != nil { t.Fatal(err) } } else { - path := utils.Cfg.ImageSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png" + path := utils.Cfg.FileSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } @@ -382,7 +382,7 @@ func TestUserUploadProfileImage(t *testing.T) { user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User) store.Must(Srv.Store.User().VerifyEmail(user.Id)) - if utils.Cfg.ImageSettings.DriverName != "" { + if utils.Cfg.FileSettings.DriverName != "" { body := &bytes.Buffer{} writer := multipart.NewWriter(body) @@ -450,19 +450,19 @@ func TestUserUploadProfileImage(t *testing.T) { Client.DoApiGet("/users/"+user.Id+"/image", "", "") - if utils.Cfg.ImageSettings.DriverName == model.IMAGE_DRIVER_S3 { + if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 { var auth aws.Auth - auth.AccessKey = utils.Cfg.ImageSettings.AmazonS3AccessKeyId - auth.SecretKey = utils.Cfg.ImageSettings.AmazonS3SecretAccessKey + auth.AccessKey = utils.Cfg.FileSettings.AmazonS3AccessKeyId + auth.SecretKey = utils.Cfg.FileSettings.AmazonS3SecretAccessKey - s := s3.New(auth, aws.Regions[utils.Cfg.ImageSettings.AmazonS3Region]) - bucket := s.Bucket(utils.Cfg.ImageSettings.AmazonS3Bucket) + s := s3.New(auth, aws.Regions[utils.Cfg.FileSettings.AmazonS3Region]) + bucket := s.Bucket(utils.Cfg.FileSettings.AmazonS3Bucket) if err := bucket.Del("teams/" + user.TeamId + "/users/" + user.Id + "/profile.png"); err != nil { t.Fatal(err) } } else { - path := utils.Cfg.ImageSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png" + path := utils.Cfg.FileSettings.Directory + "teams/" + user.TeamId + "/users/" + user.Id + "/profile.png" if err := os.Remove(path); err != nil { t.Fatal("Couldn't remove file at " + path) } diff --git a/config/config.json b/config/config.json index c0f33a346..aa92ccf4e 100644 --- a/config/config.json +++ b/config/config.json @@ -33,11 +33,11 @@ "FileFormat": "", "FileLocation": "" }, - "ImageSettings": { + "FileSettings": { "DriverName": "local", "Directory": "./data/", "EnablePublicLink": true, - "PublicLinkSalt": "LhaAWC6lYEKHTkBKsvyXNIOfUIT37AXe", + "PublicLinkSalt": "A705AklYF8MFDOfcwh3I488G8vtLlVip", "ThumbnailWidth": 120, "ThumbnailHeight": 100, "PreviewWidth": 1024, diff --git a/docker/dev/config_docker.json b/docker/dev/config_docker.json index e33396214..16a4007fa 100644 --- a/docker/dev/config_docker.json +++ b/docker/dev/config_docker.json @@ -33,7 +33,7 @@ "FileFormat": "", "FileLocation": "" }, - "ImageSettings": { + "FileSettings": { "DriverName": "local", "Directory": "/mattermost/data/", "EnablePublicLink": true, diff --git a/docker/local/config_docker.json b/docker/local/config_docker.json index e33396214..16a4007fa 100644 --- a/docker/local/config_docker.json +++ b/docker/local/config_docker.json @@ -33,7 +33,7 @@ "FileFormat": "", "FileLocation": "" }, - "ImageSettings": { + "FileSettings": { "DriverName": "local", "Directory": "/mattermost/data/", "EnablePublicLink": true, diff --git a/model/config.go b/model/config.go index 1e95277a2..69f2127b2 100644 --- a/model/config.go +++ b/model/config.go @@ -58,7 +58,7 @@ type LogSettings struct { FileLocation string } -type ImageSettings struct { +type FileSettings struct { DriverName string Directory string EnablePublicLink bool @@ -123,7 +123,7 @@ type Config struct { TeamSettings TeamSettings SqlSettings SqlSettings LogSettings LogSettings - ImageSettings ImageSettings + FileSettings FileSettings EmailSettings EmailSettings RateLimitSettings RateLimitSettings PrivacySettings PrivacySettings diff --git a/utils/config.go b/utils/config.go index c42d5c9df..5d786699b 100644 --- a/utils/config.go +++ b/utils/config.go @@ -188,9 +188,9 @@ func getClientProperties(c *model.Config) map[string]string { props["ShowEmailAddress"] = strconv.FormatBool(c.PrivacySettings.ShowEmailAddress) - props["EnablePublicLink"] = strconv.FormatBool(c.ImageSettings.EnablePublicLink) - props["ProfileHeight"] = fmt.Sprintf("%v", c.ImageSettings.ProfileHeight) - props["ProfileWidth"] = fmt.Sprintf("%v", c.ImageSettings.ProfileWidth) + props["EnablePublicLink"] = strconv.FormatBool(c.FileSettings.EnablePublicLink) + props["ProfileHeight"] = fmt.Sprintf("%v", c.FileSettings.ProfileHeight) + props["ProfileWidth"] = fmt.Sprintf("%v", c.FileSettings.ProfileWidth) return props } diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index ce7d61ca9..6fddfef07 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -9,7 +9,7 @@ var LoadingScreen = require('../loading_screen.jsx'); var EmailSettingsTab = require('./email_settings.jsx'); var LogSettingsTab = require('./log_settings.jsx'); var LogsTab = require('./logs.jsx'); -var ImageSettingsTab = require('./image_settings.jsx'); +var FileSettingsTab = require('./image_settings.jsx'); var PrivacySettingsTab = require('./privacy_settings.jsx'); var RateSettingsTab = require('./rate_settings.jsx'); var GitLabSettingsTab = require('./gitlab_settings.jsx'); @@ -61,7 +61,7 @@ export default class AdminController extends React.Component { } else if (this.state.selected === 'logs') { tab = ; } else if (this.state.selected === 'image_settings') { - tab = ; + tab = ; } else if (this.state.selected === 'privacy_settings') { tab = ; } else if (this.state.selected === 'rate_settings') { diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index 0983c1276..17ce39c7c 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -80,7 +80,7 @@ export default class AdminSidebar extends React.Component { className={this.isSelected('image_settings')} onClick={this.handleClick.bind(this, 'image_settings')} > - {'Image Settings'} + {'File Settings'}
  • diff --git a/web/react/components/admin_console/image_settings.jsx b/web/react/components/admin_console/image_settings.jsx index f84f1c735..25d5ad857 100644 --- a/web/react/components/admin_console/image_settings.jsx +++ b/web/react/components/admin_console/image_settings.jsx @@ -5,7 +5,7 @@ var Client = require('../../utils/client.jsx'); var AsyncClient = require('../../utils/async_client.jsx'); var crypto = require('crypto'); -export default class ImageSettings extends React.Component { +export default class FileSettings extends React.Component { constructor(props) { super(props); @@ -16,7 +16,7 @@ export default class ImageSettings extends React.Component { this.state = { saveNeeded: false, serverError: null, - DriverName: this.props.config.ImageSettings.DriverName + DriverName: this.props.config.FileSettings.DriverName }; } @@ -42,61 +42,61 @@ export default class ImageSettings extends React.Component { $('#save-button').button('loading'); var config = this.props.config; - config.ImageSettings.DriverName = React.findDOMNode(this.refs.DriverName).value; - config.ImageSettings.Directory = React.findDOMNode(this.refs.Directory).value; - config.ImageSettings.AmazonS3AccessKeyId = React.findDOMNode(this.refs.AmazonS3AccessKeyId).value; - config.ImageSettings.AmazonS3SecretAccessKey = React.findDOMNode(this.refs.AmazonS3SecretAccessKey).value; - config.ImageSettings.AmazonS3Bucket = React.findDOMNode(this.refs.AmazonS3Bucket).value; - config.ImageSettings.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value; - config.ImageSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked; - - config.ImageSettings.PublicLinkSalt = React.findDOMNode(this.refs.PublicLinkSalt).value.trim(); - - if (config.ImageSettings.PublicLinkSalt === '') { - config.ImageSettings.PublicLinkSalt = crypto.randomBytes(256).toString('base64').substring(0, 32); - React.findDOMNode(this.refs.PublicLinkSalt).value = config.ImageSettings.PublicLinkSalt; + config.FileSettings.DriverName = React.findDOMNode(this.refs.DriverName).value; + config.FileSettings.Directory = React.findDOMNode(this.refs.Directory).value; + config.FileSettings.AmazonS3AccessKeyId = React.findDOMNode(this.refs.AmazonS3AccessKeyId).value; + config.FileSettings.AmazonS3SecretAccessKey = React.findDOMNode(this.refs.AmazonS3SecretAccessKey).value; + config.FileSettings.AmazonS3Bucket = React.findDOMNode(this.refs.AmazonS3Bucket).value; + config.FileSettings.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value; + config.FileSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked; + + config.FileSettings.PublicLinkSalt = React.findDOMNode(this.refs.PublicLinkSalt).value.trim(); + + if (config.FileSettings.PublicLinkSalt === '') { + config.FileSettings.PublicLinkSalt = crypto.randomBytes(256).toString('base64').substring(0, 32); + React.findDOMNode(this.refs.PublicLinkSalt).value = config.FileSettings.PublicLinkSalt; } var thumbnailWidth = 120; if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) { thumbnailWidth = parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10); } - config.ImageSettings.ThumbnailWidth = thumbnailWidth; + config.FileSettings.ThumbnailWidth = thumbnailWidth; React.findDOMNode(this.refs.ThumbnailWidth).value = thumbnailWidth; var thumbnailHeight = 100; if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailHeight).value, 10))) { thumbnailHeight = parseInt(React.findDOMNode(this.refs.ThumbnailHeight).value, 10); } - config.ImageSettings.ThumbnailHeight = thumbnailHeight; + config.FileSettings.ThumbnailHeight = thumbnailHeight; React.findDOMNode(this.refs.ThumbnailHeight).value = thumbnailHeight; var previewWidth = 1024; if (!isNaN(parseInt(React.findDOMNode(this.refs.PreviewWidth).value, 10))) { previewWidth = parseInt(React.findDOMNode(this.refs.PreviewWidth).value, 10); } - config.ImageSettings.PreviewWidth = previewWidth; + config.FileSettings.PreviewWidth = previewWidth; React.findDOMNode(this.refs.PreviewWidth).value = previewWidth; var previewHeight = 0; if (!isNaN(parseInt(React.findDOMNode(this.refs.PreviewHeight).value, 10))) { previewHeight = parseInt(React.findDOMNode(this.refs.PreviewHeight).value, 10); } - config.ImageSettings.PreviewHeight = previewHeight; + config.FileSettings.PreviewHeight = previewHeight; React.findDOMNode(this.refs.PreviewHeight).value = previewHeight; var profileWidth = 128; if (!isNaN(parseInt(React.findDOMNode(this.refs.ProfileWidth).value, 10))) { profileWidth = parseInt(React.findDOMNode(this.refs.ProfileWidth).value, 10); } - config.ImageSettings.ProfileWidth = profileWidth; + config.FileSettings.ProfileWidth = profileWidth; React.findDOMNode(this.refs.ProfileWidth).value = profileWidth; var profileHeight = 128; if (!isNaN(parseInt(React.findDOMNode(this.refs.ProfileHeight).value, 10))) { profileHeight = parseInt(React.findDOMNode(this.refs.ProfileHeight).value, 10); } - config.ImageSettings.ProfileHeight = profileHeight; + config.FileSettings.ProfileHeight = profileHeight; React.findDOMNode(this.refs.ProfileHeight).value = profileHeight; Client.saveConfig( @@ -143,7 +143,7 @@ export default class ImageSettings extends React.Component { return (
    -

    {'Image Settings'}

    +

    {'File Settings'}

    @@ -185,7 +185,7 @@ export default class ImageSettings extends React.Component { id='Directory' ref='Directory' placeholder='Ex "./data/"' - defaultValue={this.props.config.ImageSettings.Directory} + defaultValue={this.props.config.FileSettings.Directory} onChange={this.handleChange} disabled={!enableFile} /> @@ -207,7 +207,7 @@ export default class ImageSettings extends React.Component { id='AmazonS3AccessKeyId' ref='AmazonS3AccessKeyId' placeholder='Ex "AKIADTOVBGERKLCBV"' - defaultValue={this.props.config.ImageSettings.AmazonS3AccessKeyId} + defaultValue={this.props.config.FileSettings.AmazonS3AccessKeyId} onChange={this.handleChange} disabled={!enableS3} /> @@ -229,7 +229,7 @@ export default class ImageSettings extends React.Component { id='AmazonS3SecretAccessKey' ref='AmazonS3SecretAccessKey' placeholder='Ex "jcuS8PuvcpGhpgHhlcpT1Mx42pnqMxQY"' - defaultValue={this.props.config.ImageSettings.AmazonS3SecretAccessKey} + defaultValue={this.props.config.FileSettings.AmazonS3SecretAccessKey} onChange={this.handleChange} disabled={!enableS3} /> @@ -251,7 +251,7 @@ export default class ImageSettings extends React.Component { id='AmazonS3Bucket' ref='AmazonS3Bucket' placeholder='Ex "mattermost-media"' - defaultValue={this.props.config.ImageSettings.AmazonS3Bucket} + defaultValue={this.props.config.FileSettings.AmazonS3Bucket} onChange={this.handleChange} disabled={!enableS3} /> @@ -273,7 +273,7 @@ export default class ImageSettings extends React.Component { id='AmazonS3Region' ref='AmazonS3Region' placeholder='Ex "us-east-1"' - defaultValue={this.props.config.ImageSettings.AmazonS3Region} + defaultValue={this.props.config.FileSettings.AmazonS3Region} onChange={this.handleChange} disabled={!enableS3} /> @@ -295,7 +295,7 @@ export default class ImageSettings extends React.Component { id='ThumbnailWidth' ref='ThumbnailWidth' placeholder='Ex "120"' - defaultValue={this.props.config.ImageSettings.ThumbnailWidth} + defaultValue={this.props.config.FileSettings.ThumbnailWidth} onChange={this.handleChange} />

    {'Width of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}

    @@ -316,7 +316,7 @@ export default class ImageSettings extends React.Component { id='ThumbnailHeight' ref='ThumbnailHeight' placeholder='Ex "100"' - defaultValue={this.props.config.ImageSettings.ThumbnailHeight} + defaultValue={this.props.config.FileSettings.ThumbnailHeight} onChange={this.handleChange} />

    {'Height of thumbnails generated from uploaded images. Updating this value changes how thumbnail images render in future, but does not change images created in the past.'}

    @@ -337,7 +337,7 @@ export default class ImageSettings extends React.Component { id='PreviewWidth' ref='PreviewWidth' placeholder='Ex "1024"' - defaultValue={this.props.config.ImageSettings.PreviewWidth} + defaultValue={this.props.config.FileSettings.PreviewWidth} onChange={this.handleChange} />

    {'Maximum width of preview image. Updating this value changes how preview images render in future, but does not change images created in the past.'}

    @@ -358,7 +358,7 @@ export default class ImageSettings extends React.Component { id='PreviewHeight' ref='PreviewHeight' placeholder='Ex "0"' - defaultValue={this.props.config.ImageSettings.PreviewHeight} + defaultValue={this.props.config.FileSettings.PreviewHeight} onChange={this.handleChange} />

    {'Maximum height of preview image ("0": Sets to auto-size). Updating this value changes how preview images render in future, but does not change images created in the past.'}

    @@ -379,7 +379,7 @@ export default class ImageSettings extends React.Component { id='ProfileWidth' ref='ProfileWidth' placeholder='Ex "1024"' - defaultValue={this.props.config.ImageSettings.ProfileWidth} + defaultValue={this.props.config.FileSettings.ProfileWidth} onChange={this.handleChange} />

    {'Width of profile picture.'}

    @@ -400,7 +400,7 @@ export default class ImageSettings extends React.Component { id='ProfileHeight' ref='ProfileHeight' placeholder='Ex "0"' - defaultValue={this.props.config.ImageSettings.ProfileHeight} + defaultValue={this.props.config.FileSettings.ProfileHeight} onChange={this.handleChange} />

    {'Height of profile picture.'}

    @@ -421,7 +421,7 @@ export default class ImageSettings extends React.Component { name='EnablePublicLink' value='true' ref='EnablePublicLink' - defaultChecked={this.props.config.ImageSettings.EnablePublicLink} + defaultChecked={this.props.config.FileSettings.EnablePublicLink} onChange={this.handleChange} /> {'true'} @@ -431,7 +431,7 @@ export default class ImageSettings extends React.Component { type='radio' name='EnablePublicLink' value='false' - defaultChecked={!this.props.config.ImageSettings.EnablePublicLink} + defaultChecked={!this.props.config.FileSettings.EnablePublicLink} onChange={this.handleChange} /> {'false'} @@ -454,7 +454,7 @@ export default class ImageSettings extends React.Component { id='PublicLinkSalt' ref='PublicLinkSalt' placeholder='Ex "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6"' - defaultValue={this.props.config.ImageSettings.PublicLinkSalt} + defaultValue={this.props.config.FileSettings.PublicLinkSalt} onChange={this.handleChange} />

    {'32-character salt added to signing of public image links.'}

    @@ -491,6 +491,6 @@ export default class ImageSettings extends React.Component { } } -ImageSettings.propTypes = { +FileSettings.propTypes = { config: React.PropTypes.object }; diff --git a/web/react/components/signup_team.jsx b/web/react/components/signup_team.jsx index 7f320e0b2..4112138fa 100644 --- a/web/react/components/signup_team.jsx +++ b/web/react/components/signup_team.jsx @@ -4,7 +4,7 @@ const ChoosePage = require('./team_signup_choose_auth.jsx'); const EmailSignUpPage = require('./team_signup_with_email.jsx'); const SSOSignupPage = require('./team_signup_with_sso.jsx'); -var Constants = require('../utils/constants.jsx'); +const Constants = require('../utils/constants.jsx'); export default class TeamSignUp extends React.Component { constructor(props) { -- cgit v1.2.3-1-g7c22 From 2f72d4702b29477fab706a693f2bc4efb8cefd66 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 23 Sep 2015 14:32:44 -0700 Subject: fixing segment bug --- web/templates/head.html | 1 - 1 file changed, 1 deletion(-) diff --git a/web/templates/head.html b/web/templates/head.html index e1f2fe43f..a65a28566 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -62,7 +62,6 @@ createdAt: user.create_at, username: user.username, team_id: user.team_id, - team_domain: window.getSubDomain(), id: user.id }); } -- cgit v1.2.3-1-g7c22 From a9c4f5efd0c1e6927cdec99a98c661fcc0ef6c89 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Wed, 23 Sep 2015 14:35:05 -0700 Subject: fixing segment bug --- web/templates/head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/templates/head.html b/web/templates/head.html index a65a28566..2b83119d8 100644 --- a/web/templates/head.html +++ b/web/templates/head.html @@ -53,7 +53,7 @@