Merge pull request #304 from RocketChat/settings

Initial version of Settings Page
pull/305/head
Gabriel Engel 11 years ago
commit d2ee69ce37
  1. 2
      .meteor/packages
  2. 15
      client/routes/router.coffee
  3. 107
      client/views/app/settings.html
  4. 18
      client/views/main.coffee
  5. 18
      client/views/main.html
  6. 31
      client/views/settings/settings.coffee
  7. 55
      client/views/settings/settings.html
  8. 1
      i18n/en.i18n.json
  9. 5
      packages/rocketchat-ldap/i18n/en.i18n.json
  10. 5
      packages/rocketchat-ldap/i18n/pt.i18n.json
  11. 8
      packages/rocketchat-ldap/lib/ldapjs.js
  12. 0
      packages/rocketchat-ldap/package-tap.i18n
  13. 8
      packages/rocketchat-ldap/package.js
  14. 23
      packages/rocketchat-lib/lib/settings.coffee
  15. 13
      packages/rocketchat-lib/package.js
  16. 4
      packages/rocketchat-lib/server/cdn.coffee
  17. 2
      packages/rocketchat-lib/settings/client/startup.coffee
  18. 8
      packages/rocketchat-lib/settings/lib/rocketchat.coffee
  19. 19
      packages/rocketchat-lib/settings/lib/settings.coffee
  20. 41
      packages/rocketchat-lib/settings/server/methods.coffee
  21. 13
      packages/rocketchat-lib/settings/server/publication.coffee
  22. 24
      packages/rocketchat-lib/settings/server/startup.coffee
  23. 1043
      public/images/logo/icon-dark.ai
  24. 38
      server/lib/_settings.coffee
  25. 2
      server/lib/accounts.coffee
  26. 8
      server/lib/ldap.coffee
  27. 1
      server/publications/userData.coffee
  28. 14
      server/startup/avatar.coffee
  29. 15
      server/startup/migrations/v8.coffee

@ -29,7 +29,6 @@ konecty:mongo-counter
konecty:multiple-instances-status
konecty:nrr
konecty:user-presence
meteorhacks:kadira
mizzao:autocomplete
mizzao:timesync
momentjs:moment
@ -59,3 +58,4 @@ tmeasday:errors
todda00:friendly-slugs
underscorestring:underscore.string
yasaricli:slugify
meteorhacks:kadira

@ -64,16 +64,23 @@ Router.route '/home',
onAfterAction: ->
KonchatNotification.getDesktopPermission()
Router.route '/settings',
Router.route '/settings/:group?',
name: 'settings'
onBeforeAction: ->
if Meteor.user()?.admin isnt true
Router.go('home')
@next()
waitOn: ->
return Meteor.subscribe 'admin-settings'
data: ->
return {
group: if @params.group then @params.group else Settings.findOne({ type: 'group' })?._id
}
action: ->
this.render('settings')
onAfterAction: ->
KonchatNotification.getDesktopPermission()
Router.route '/room/:_id',
name: 'room'

@ -1,107 +0,0 @@
<template name="settings">
<section class="page-container page-home page-static">
<header class="fixed-title">
<div class="burger">
<i></i>
<i></i>
<i></i>
</div>
<h2>
<span class="room-title">{{_ "App_Settings"}}</span>
</h2>
</header>
<div class="content">
<div class="info">
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
</div>
<div class="rocket-form">
<fieldset>
<legend>
<h3>This is another section</h3>
<p>This is a configuration text. With configuration info</p>
</legend>
<div class="input-line double-col">
<label>Input Field</label>
<div>
<input type="text" name="input-name" />
</div>
</div>
<div class="input-line double-col">
<label>Select Field</label>
<div>
<select name="select">
<option value="1">Option A</option>
<option value="1">Option B</option>
<option value="1">Option C</option>
<option value="1">Option D</option>
<option value="1">Option E</option>
</select>
</div>
</div>
</fieldset>
<fieldset>
<legend>
<h3>This is another section</h3>
<p>This is a configuration text. With configuration info</p>
</legend>
<div class="input-line double-col">
<label>Radio field</label>
<div>
<label><input type="radio" name="pandora" value="1" /> Calazar</label>
<label><input type="radio" name="pandora" value="2" /> Genoveve</label>
</div>
</div>
<div class="input-line double-col">
<label>Checkbox field</label>
<div>
<label><input type="checkbox" name="pandora" value="1" /> Calazar</label>
<label><input type="checkbox" name="pandora" value="2" /> Genoveve</label>
</div>
</div>
</fieldset>
<fieldset>
<legend>
<h3>This is another section</h3>
<p>This is a configuration text. With configuration info</p>
</legend>
<div class="input-line double-col">
<label>Input Field</label>
<div>
<input type="text" name="input-name" />
</div>
</div>
<div class="input-line double-col">
<label>Select Field</label>
<div>
<select name="select">
<option value="1">Option A</option>
<option value="1">Option B</option>
<option value="1">Option C</option>
<option value="1">Option D</option>
<option value="1">Option E</option>
</select>
</div>
</div>
</fieldset>
<div class="submit">
<button class="button"><i class="icon-send"></i><span>Save changes</span></button>
</div>
</div>
</div>
</section>
<!-- <section class="flex-tab">
<div class="control">
<button class="more"><span class="arrow {{arrowPosition}}"></span></button>
</div>
<div class="content">
<div class="list-view">
<div class="status">
<h2>{{_ "Chat_Rooms"}}</h2>
<p>
{{{_ "Showing_online_users" total_online=1 total=1}}}
</p>
</div>
</div>
</div>
</section> -->
</template>

@ -0,0 +1,18 @@
Template.body.onRendered ->
dataLayerComputation = Tracker.autorun ->
w = window
d = document
s = 'script'
l = 'dataLayer'
i = RocketChat.settings.get 'API_Analytics'
if i
do (w,d,s,l,i) ->
w[l] = w[l] || []
w[l].push {'gtm.start': new Date().getTime(), event:'gtm.js'}
f = d.getElementsByTagName(s)[0]
j = d.createElement(s)
dl = if l isnt 'dataLayer' then '&l=' + l else ''
j.async = true
j.src = '//www.googletagmanager.com/gtm.js?id=' + i + dl
f.parentNode.insertBefore j, f
dataLayerComputation.stop()

@ -40,22 +40,4 @@
</head>
<body>
<!-- Google Tag Manager -->
<script>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({
'gtm.start': new Date().getTime(),
event: 'gtm.js'
});
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src =
'//www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, 'script', 'dataLayer', 'GTM-MLJ76N');
</script>
<!-- End Google Tag Manager -->
</body>

@ -0,0 +1,31 @@
Template.settings.helpers
groups: ->
return Settings.find({type: 'group'}).fetch()
group: ->
return Settings.findOne { _id: @group, type: 'group' }
settings: ->
return Settings.find({ group: @group }).fetch()
flexOpened: ->
return 'opened' if Session.equals('flexOpened', true)
arrowPosition: ->
console.log 'room.helpers arrowPosition' if window.rocketDebug
return 'left' unless Session.equals('flexOpened', true)
label: ->
return TAPi18next.t @i18nLabel
Template.settings.events
"click .burger": ->
chatContainer = $("#rocket-chat")
if chatContainer.hasClass("menu-closed")
chatContainer.removeClass("menu-closed").addClass("menu-opened")
else
chatContainer.addClass("menu-closed").removeClass("menu-opened")
"click .flex-tab .more": (event) ->
console.log 'settings click .flex-tab .more' if window.rocketDebug
Session.set('flexOpened', !Session.get('flexOpened'))
Template.settings.onRendered ->
console.log 'room.onRendered' if window.rocketDebug
Session.set 'flexOpened', true
FlexTab.check()

@ -0,0 +1,55 @@
<template name="settings">
<section class="page-container page-home page-static">
<head class="fixed-title">
<div>
<div class="burger">
<i></i>
<i></i>
<i></i>
</div>
<h2>
<span class="room-title">{{_ "App_Settings"}}</span>
</h2>
</div>
</head>
<div class="content">
<h3>{{label}}</h3>
<div class="rocket-form">
<fieldset>
<legend>
<!-- <h3>This is another section</h3>
<p>This is a configuration text. With configuration info</p> -->
</legend>
{{#each settings}}
<div class="input-line double-col">
<label>{{label}}</label>
<div>
<input type="text" name="input-name" value="{{value}}" />
</div>
</div>
{{/each}}
</fieldset>
</div>
</div>
</section>
<section class="flex-tab">
<div class="control">
<button class="more"><span class="arrow {{arrowPosition}}"></span></button>
<div class="search-form">
<div class="input-line search">
<input type="text" class="search" placeholder={{_ "Search_settings"}} />
<i class="icon-plus"></i>
</div>
</div>
</div>
<div class="content">
<ul class='list cf_ lines'>
{{#each groups}}
<li>
<a href="{{pathFor 'settings' group=_id}}">{{_ i18nLabel}}</a>
</li>
{{/each}}
</ul>
</div>
</section>
</template>

@ -121,6 +121,7 @@
"Room_name_changed_successfully" : "Room name changed successfully",
"Save" : "Save",
"Search" : "Search",
"Search_settings" : "Search settings",
"See_all" : "See all",
"See_only_online" : "Only online",
"Select_an_avatar" : "Select an avatar",

@ -0,0 +1,5 @@
{
"LDAP_Url" : "LDAP URL",
"LDAP_Port" : "LDAP Port",
"LDAP_Dn" : "LDAP DN"
}

@ -0,0 +1,5 @@
{
"LDAP_Url" : "URL LDAP",
"LDAP_Port" : "Porta LDAP",
"LDAP_Dn" : "DN LDAP"
}

@ -1 +1,7 @@
MeteorWrapperLdapjs = Npm.require('ldapjs');
MeteorWrapperLdapjs = Npm.require('ldapjs');
Meteor.startup(function() {
RocketChat.settings.add('LDAP_Url', '', { type: 'string', group: 'Accounts', i18nLabel: 'rocketchat-ldap:LDAP_Url' });
RocketChat.settings.add('LDAP_Port', '', { type: 'string', group: 'Accounts', i18nLabel: 'rocketchat-ldap:LDAP_Port' });
RocketChat.settings.add('LDAP_DN', '', { type: 'string', group: 'Accounts', i18nLabel: 'rocketchat-ldap:LDAP_Dn', public: true });
});

@ -12,6 +12,9 @@ Npm.depends({
Package.onUse(function(api) {
api.versionsFrom('1.0.3.1');
api.use(["tap:i18n@1.5.1"], ["client", "server"]);
api.add_files("package-tap.i18n", ["client", "server"]);
api.use(['templating'], 'client');
api.use(['accounts-base', 'accounts-password'], 'server');
@ -19,6 +22,11 @@ Package.onUse(function(api) {
api.addFiles(['ldap_client.js'], 'client');
api.addFiles(['ldap_server.js', 'lib/ldapjs.js'], 'server');
api.add_files([
"i18n/en.i18n.json",
"i18n/pt.i18n.json"
], ["client", "server"]);
api.export('LDAP', 'server');
api.export('LDAP_DEFAULTS', 'server');
api.export([

@ -1,23 +0,0 @@
###
# Setting hooks provide an easy way to add extra steps to common operations.
# @namespace RocketChat.settings
###
RocketChat.settings = {}
###
# Add a setting function to a hook
# @param {String} hook - The name of the hook
# @param {Function} setting - The setting function
###
RocketChat.settings.add = (setting) ->
return
RocketChat.settings.addGroup = (settingsGroup) ->
return
RocketChat.settings.addPage = (settingsPage) ->
return
RocketChat.settings.startup = () ->
return

@ -19,6 +19,19 @@ Package.onUse(function(api) {
api.addFiles('lib/callbacks.coffee', ['server', 'client']);
api.addFiles('server/sendMessage.coffee', ['server']);
api.addFiles([
'settings/lib/settings.coffee',
'settings/lib/rocketchat.coffee'
], ['server', 'client']);
api.addFiles('settings/client/startup.coffee', ['client']);
api.addFiles([
'settings/server/methods.coffee',
'settings/server/publication.coffee',
'settings/server/startup.coffee'
], ['server']);
api.addFiles('server/cdn.coffee', ['server']);
api.export(['RocketChat'], ['server', 'client']);
});

@ -0,0 +1,4 @@
Meteor.startup ->
cdnPrefix = RocketChat.settings.get 'CDN_PREFIX'
if cdnPrefix?
WebAppInternals.setBundledJsCssPrefix cdnPrefix

@ -0,0 +1,2 @@
Meteor.startup ->
Meteor.subscribe 'settings'

@ -0,0 +1,8 @@
###
# RocketChat.settings holds all packages settings
# @namespace RocketChat.settings
###
RocketChat.settings = {}
RocketChat.settings.get = (_id) ->
return Meteor.settings?[_id]

@ -0,0 +1,19 @@
@Settings = new Meteor.Collection 'settings'
Settings.find().observe
added: (record) ->
Meteor.settings ?= {}
Meteor.settings[record._id] = record.value
if process?
process.env ?= {}
process.env[record._id] = record.value
changed: (record) ->
Meteor.settings?[record._id] = record.value
if process?
process.env[record._id] = record.value
removed: (record) ->
delete Meteor.settings?[record._id]
delete process?.env?[record._id]

@ -0,0 +1,41 @@
###
# Add a setting
# @param {String} _id
# @param {Mixed} value
# @param {Object} setting
###
RocketChat.settings.add = (_id, value, options = {}) ->
if not _id or not value?
return false
console.log '[functions] RocketChat.settings.add -> '.green, 'arguments:', arguments
if Meteor.settings?[_id]?
value = Meteor.settings[_id]
updateSettings =
i18nLabel: options.i18nLabel or _id
updateSettings.type = options.type if options.type
updateSettings.group = options.group if options.group
updateSettings.public = options.public if options.public
return Settings.upsert { _id: _id }, { $setOnInsert: { value: value }, $set: updateSettings }
###
# Add a setting group
# @param {String} _id
###
RocketChat.settings.addGroup = (_id, options = {}) ->
if not _id
return false
console.log '[functions] RocketChat.settings.addGroup -> '.green, 'arguments:', arguments
updateSettings =
i18nLabel: options.i18nLabel or _id
type: 'group'
return Settings.upsert { _id: _id }, { $set: updateSettings }

@ -0,0 +1,13 @@
Meteor.publish 'settings', ->
console.log '[publish] settings'.green
return Settings.find { public: true }, { fields: _id: 1, value: 1 }
Meteor.publish 'admin-settings', ->
console.log '[publish] admin-settings'.green
unless @userId
return @ready()
user = Meteor.users.findOne @userId
if user.admin
return Settings.find()

@ -0,0 +1,24 @@
Meteor.startup ->
RocketChat.settings.addGroup 'Accounts'
RocketChat.settings.add 'Accounts_RegistrationRequired', true, { type: 'boolean', group: 'Accounts', public: true }
RocketChat.settings.add 'Accounts_EmailVerification', false, { type: 'boolean', group: 'Accounts', public: true }
RocketChat.settings.addGroup 'API'
RocketChat.settings.add 'API_Analytics', '', { type: 'string', group: 'API', public: true }
RocketChat.settings.add 'API_Piwik_URL', '', { type: 'string', group: 'API', public: true }
RocketChat.settings.add 'API_Piwik_ID', '', { type: 'string', group: 'API', public: true }
RocketChat.settings.add 'API_Embed', '', { type: 'boolean', group: 'API' }
RocketChat.settings.addGroup 'SMTP'
RocketChat.settings.add 'SMTP_Host', '', { type: 'string', group: 'SMTP' }
RocketChat.settings.add 'SMTP_Port', '', { type: 'string', group: 'SMTP' }
RocketChat.settings.add 'SMTP_Security', '', { type: 'string', group: 'SMTP' }
RocketChat.settings.add 'SMTP_Username', '', { type: 'string', group: 'SMTP' }
RocketChat.settings.add 'SMTP_Password', '', { type: 'string', group: 'SMTP' }
RocketChat.settings.addGroup 'Message'
RocketChat.settings.add 'Message_Edit', '', { type: 'string', group: 'Message' }
RocketChat.settings.add 'Message_Delete', '', { type: 'string', group: 'Message' }
RocketChat.settings.add 'Message_ShowEditedStatus', '', { type: 'string', group: 'Message' }
RocketChat.settings.add 'Message_ShowDeletedStatus', '', { type: 'string', group: 'Message' }
RocketChat.settings.add 'Message_KeepStatusHistory', '', { type: 'string', group: 'Message' }

File diff suppressed because one or more lines are too long

@ -1,38 +0,0 @@
@Settings = new Meteor.Collection 'settings'
loadEnvConfigs = (settings) ->
if settings.ENV?
for key, value of settings.ENV
process.env[key] = value
configLoginServices = (settings) ->
settings?['login-services']?.forEach (config) ->
ServiceConfiguration.configurations.remove
service: config.service
ServiceConfiguration.configurations.insert config
configCDN = (settings) ->
if settings.CDN_PREFIX?
WebAppInternals.setBundledJsCssPrefix settings.CDN_PREFIX
configKadira = (settings) ->
if settings.kadira?
Kadira.connect(settings.kadira.appId, settings.kadira.appSecret)
Settings.find({_id: 'settings'}).observe
added: (settings) ->
Meteor.settings = settings
__meteor_runtime_config__?.PUBLIC_SETTINGS = Meteor.settings?.public
configLoginServices settings
loadEnvConfigs settings
configCDN settings
configKadira settings
changed: (settings) ->
Meteor.settings = settings
__meteor_runtime_config__?.PUBLIC_SETTINGS = Meteor.settings?.public
configLoginServices settings
loadEnvConfigs settings
configCDN settings
configKadira settings

@ -50,7 +50,7 @@ Accounts.validateLoginAttempt (login) ->
if login.allowed isnt true
return login.allowed
if login.type is 'password' and Meteor.settings.denyUnverifiedEmails is true
if login.type is 'password' and RocketChat.settings.get 'Accounts_denyUnverifiedEmails' is true
validEmail = login.user.emails.filter (email) ->
return email.verified is true

@ -1,3 +1,5 @@
LDAP_DEFAULTS.url = "ldap://ldap.forumsys.com"
LDAP_DEFAULTS.port = '389'
LDAP_DEFAULTS.dn = false
Meteor.startup ->
if RocketChat.settings.get 'LDAP_URL'
LDAP_DEFAULTS.url = RocketChat.settings.get 'LDAP_URL'
LDAP_DEFAULTS.port = RocketChat.settings.get 'LDAP_PORT' if RocketChat.settings.get 'LDAP_PORT'
LDAP_DEFAULTS.dn = RocketChat.settings.get 'LDAP_DN' or false

@ -12,3 +12,4 @@ Meteor.publish 'userData', ->
statusDefault: 1
statusConnection: 1
avatarOrigin: 1
admin: 1

@ -1,8 +1,8 @@
Meteor.startup ->
storeType = 'GridFS'
if Meteor.settings?.public?.avatarStore?.type?
storeType = Meteor.settings.public.avatarStore.type
if RocketChat.settings.get 'avatarStore_type'
storeType = RocketChat.settings.get 'avatarStore_type'
RocketChatStore = RocketChatFile[storeType]
@ -12,16 +12,16 @@ Meteor.startup ->
console.log "Using #{storeType} for Avatar storage".green
transformWrite = undefined
if Meteor.settings?.public?.avatarStore?.size?.height?
height = Meteor.settings.public.avatarStore.size.height
width = Meteor.settings.public.avatarStore.size.width
if RocketChat.settings.get 'avatarStore_size_height'
height = RocketChat.settings.get 'avatarStore_size_height'
width = RocketChat.settings.get 'avatarStore_size_width'
transformWrite = (file, readStream, writeStream) ->
RocketChatFile.gm(readStream, file.fileName).background('#ffffff').resize(width, height+'^>').gravity('Center').extent(width, height).stream('jpeg').pipe(writeStream)
path = "~/uploads"
if Meteor.settings?.public?.avatarStore?.path?
path = Meteor.settings.public.avatarStore.path
if RocketChat.settings.get 'avatarStore_path'
path = RocketChat.settings.get 'avatarStore_path'
@RocketChatFileAvatarInstance = new RocketChatStore
name: 'avatars'

@ -0,0 +1,15 @@
Meteor.startup ->
Migrations.add
version: 8
up: ->
console.log 'Load old settings record'
settings = Settings.findOne({ _id: 'settings' })
if settings
Settings.insert { _id: 'CDN_PREFIX', value: settings.CDN_PREFIX, type: 'string', group: 'General' } if settings.CDN_PREFIX?
Settings.insert { _id: 'MAIL_URL', value: settings.ENV.MAIL_URL, type: 'string', group: 'SMTP' } if settings.ENV?.MAIL_URL?
Settings.insert { _id: 'Accounts_denyUnverifiedEmails', value: settings.denyUnverifiedEmails, type: 'boolean', group: 'Accounts' } if settings.denyUnverifiedEmails?
Settings.insert { _id: 'KADIRA_APP_ID', value: settings.kadira.appId, type: 'string', group: 'API' } if settings.kadira?.appId?
Settings.insert { _id: 'KADIRA_APP_SECRET', value: settings.kadira.appSecret, type: 'string', group: 'API' } if settings.kadira?.appSecret?
Settings.insert { _id: 'avatarStore_type', value: settings.public.avatarStore.type, type: 'string', group: 'API' } if settings.public?.avatarStore?.type?
Settings.insert { _id: 'avatarStore_path', value: settings.public.avatarStore.path, type: 'string', group: 'API' } if settings.public?.avatarStore?.path?
Settings.remove { _id: 'settings' }
Loading…
Cancel
Save