Compare commits

...

17 Commits

Author SHA1 Message Date
Bernie Chiu c361a7a201 Fix check box selections appearance
Conflicts:
	vendor/built_in_modules/ask_new/app/controllers/panel/ask/back_end/ask_replies_controller.rb
2013-09-13 15:43:14 +08:00
thomaschen b7bf180df2 fix frontend ask_category error 2013-09-13 15:43:14 +08:00
Bernie Chiu 71dad22b04 Add dynamic checkboxes
Conflicts:
	vendor/built_in_modules/ask_new/app/views/panel/ask/back_end/ask_questions/edit.html.erb
2013-09-13 15:43:14 +08:00
thomaschen 883496ede1 add multi deliver request 2013-09-13 15:43:14 +08:00
Bernie Chiu 0a1ebf18e3 Add check box array 2013-09-13 15:43:13 +08:00
thomaschen 3f9cdec426 add option for dep_dns 2013-09-13 15:43:13 +08:00
thomaschen 24b9f4015b add checkboxes for 11 dep in edit view 2013-09-13 15:43:13 +08:00
thomaschen 1237a111ca add transfered_category if not exist. change transfered reply's status to 待處理(轉). showing request code if error. 2013-09-13 15:43:13 +08:00
Bernie Chiu 64e14d42e2 Allow ask_question transter 2013-09-13 15:43:13 +08:00
thomaschen cc7a4ffb6d add response(temp) 2013-09-13 15:43:13 +08:00
Bernie Chiu da40c2b669 Allow sending request and getting response 2013-09-13 15:43:13 +08:00
thomaschen bf5416095e add auth_request route and controller 2013-09-13 15:43:13 +08:00
Bernie Chiu 8cd27e26e2 Fixed untracked files
Conflicts:
	config/mongoid.yml
2013-09-13 15:43:13 +08:00
thomaschen d98d008806 add sending post request function 2013-09-13 15:43:13 +08:00
chris cd26b880fb Change the logo and favicon 2013-09-13 15:42:52 +08:00
chris 7c398ce4fe Changes for NTU General Affairs 2013-09-13 15:10:27 +08:00
chris d766eea9f4 Changes for NTU common
Conflicts:
	lib/tasks/migrate.rake

Conflicts:
	lib/tasks/migrate.rake

Conflicts:
	config/resque_schedule.yml
	lib/tasks/migrate.rake
2013-09-13 15:10:10 +08:00
113 changed files with 45815 additions and 124 deletions

2
.gitignore vendored
View File

@ -4,6 +4,8 @@
.rvmrc
Gemfile.lock
Procfile
log/*
db/*.sqlite3
log/*.log

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,23 @@
!function ($) {
$.fn.cardCheck = function(param) {
_defaultSettings = {
check: '',
};
_set = $.extend(_defaultSettings, param);
$card = $(this);
$check = _set.check;
$check.each(function(){
if($(this).attr('checked')) {
$(this).parent($card).addClass("active");
}
});
$card.on('click', function() {
$(this).toggleClass('active')
});
}
}(window.jQuery);
$(function(){
$('.checkbox-card > li').cardCheck({
check: $('.checkbox-card > li input[type="checkbox"]'),
});
});

View File

@ -0,0 +1,752 @@
/*! nanoScrollerJS - v0.7.2
* http://jamesflorentino.github.com/nanoScrollerJS/
* Copyright (c) 2013 James Florentino; Licensed MIT */
(function($, window, document) {
"use strict";
var BROWSER_IS_IE7, BROWSER_SCROLLBAR_WIDTH, DOMSCROLL, DOWN, DRAG, KEYDOWN, KEYUP, MOUSEDOWN, MOUSEMOVE, MOUSEUP, MOUSEWHEEL, NanoScroll, PANEDOWN, RESIZE, SCROLL, SCROLLBAR, TOUCHMOVE, UP, WHEEL, defaults, getBrowserScrollbarWidth;
defaults = {
/**
a classname for the pane element.
@property paneClass
@type String
@default 'pane'
*/
paneClass: 'pane',
/**
a classname for the slider element.
@property sliderClass
@type String
@default 'slider'
*/
sliderClass: 'slider',
/**
a classname for the content element.
@property contentClass
@type String
@default 'content'
*/
contentClass: 'content',
/**
a setting to enable native scrolling in iOS devices.
@property iOSNativeScrolling
@type Boolean
@default false
*/
iOSNativeScrolling: false,
/**
a setting to prevent the rest of the page being
scrolled when user scrolls the `.content` element.
@property preventPageScrolling
@type Boolean
@default false
*/
preventPageScrolling: false,
/**
a setting to disable binding to the resize event.
@property disableResize
@type Boolean
@default false
*/
disableResize: false,
/**
a setting to make the scrollbar always visible.
@property alwaysVisible
@type Boolean
@default false
*/
alwaysVisible: false,
/**
a default timeout for the `flash()` method.
@property flashDelay
@type Number
@default 1500
*/
flashDelay: 1500,
/**
a minimum height for the `.slider` element.
@property sliderMinHeight
@type Number
@default 20
*/
sliderMinHeight: 20,
/**
a maximum height for the `.slider` element.
@property sliderMaxHeight
@type Number
@default null
*/
sliderMaxHeight: null
};
/**
@property SCROLLBAR
@type String
@static
@final
@private
*/
SCROLLBAR = 'scrollbar';
/**
@property SCROLL
@type String
@static
@final
@private
*/
SCROLL = 'scroll';
/**
@property MOUSEDOWN
@type String
@final
@private
*/
MOUSEDOWN = 'mousedown';
/**
@property MOUSEMOVE
@type String
@static
@final
@private
*/
MOUSEMOVE = 'mousemove';
/**
@property MOUSEWHEEL
@type String
@final
@private
*/
MOUSEWHEEL = 'mousewheel';
/**
@property MOUSEUP
@type String
@static
@final
@private
*/
MOUSEUP = 'mouseup';
/**
@property RESIZE
@type String
@final
@private
*/
RESIZE = 'resize';
/**
@property DRAG
@type String
@static
@final
@private
*/
DRAG = 'drag';
/**
@property UP
@type String
@static
@final
@private
*/
UP = 'up';
/**
@property PANEDOWN
@type String
@static
@final
@private
*/
PANEDOWN = 'panedown';
/**
@property DOMSCROLL
@type String
@static
@final
@private
*/
DOMSCROLL = 'DOMMouseScroll';
/**
@property DOWN
@type String
@static
@final
@private
*/
DOWN = 'down';
/**
@property WHEEL
@type String
@static
@final
@private
*/
WHEEL = 'wheel';
/**
@property KEYDOWN
@type String
@static
@final
@private
*/
KEYDOWN = 'keydown';
/**
@property KEYUP
@type String
@static
@final
@private
*/
KEYUP = 'keyup';
/**
@property TOUCHMOVE
@type String
@static
@final
@private
*/
TOUCHMOVE = 'touchmove';
/**
@property BROWSER_IS_IE7
@type Boolean
@static
@final
@private
*/
BROWSER_IS_IE7 = window.navigator.appName === 'Microsoft Internet Explorer' && /msie 7./i.test(window.navigator.appVersion) && window.ActiveXObject;
/**
@property BROWSER_SCROLLBAR_WIDTH
@type Number
@static
@default null
@private
*/
BROWSER_SCROLLBAR_WIDTH = null;
/**
Returns browser's native scrollbar width
@method getBrowserScrollbarWidth
@return {Number} the scrollbar width in pixels
@static
@private
*/
getBrowserScrollbarWidth = function() {
var outer, outerStyle, scrollbarWidth;
outer = document.createElement('div');
outerStyle = outer.style;
outerStyle.position = 'absolute';
outerStyle.width = '100px';
outerStyle.height = '100px';
outerStyle.overflow = SCROLL;
outerStyle.top = '-9999px';
document.body.appendChild(outer);
scrollbarWidth = outer.offsetWidth - outer.clientWidth;
document.body.removeChild(outer);
return scrollbarWidth;
};
/**
@class NanoScroll
@param element {HTMLElement|Node} the main element
@param options {Object} nanoScroller's options
@constructor
*/
NanoScroll = (function() {
function NanoScroll(el, options) {
this.el = el;
this.options = options;
BROWSER_SCROLLBAR_WIDTH || (BROWSER_SCROLLBAR_WIDTH = getBrowserScrollbarWidth());
this.$el = $(this.el);
this.doc = $(document);
this.win = $(window);
this.$content = this.$el.children("." + options.contentClass);
this.$content.attr('tabindex', 0);
this.content = this.$content[0];
if (this.options.iOSNativeScrolling && (this.el.style.WebkitOverflowScrolling != null)) {
this.nativeScrolling();
} else {
this.generate();
}
this.createEvents();
this.addEvents();
this.reset();
}
/**
Prevents the rest of the page being scrolled
when user scrolls the `.content` element.
@method preventScrolling
@param event {Event}
@param direction {String} Scroll direction (up or down)
@private
*/
NanoScroll.prototype.preventScrolling = function(e, direction) {
if (!this.isActive) {
return;
}
if (e.type === DOMSCROLL) {
if (direction === DOWN && e.originalEvent.detail > 0 || direction === UP && e.originalEvent.detail < 0) {
e.preventDefault();
}
} else if (e.type === MOUSEWHEEL) {
if (!e.originalEvent || !e.originalEvent.wheelDelta) {
return;
}
if (direction === DOWN && e.originalEvent.wheelDelta < 0 || direction === UP && e.originalEvent.wheelDelta > 0) {
e.preventDefault();
}
}
};
/**
Enable iOS native scrolling
*/
NanoScroll.prototype.nativeScrolling = function() {
this.$content.css({
WebkitOverflowScrolling: 'touch'
});
this.iOSNativeScrolling = true;
this.isActive = true;
};
/**
Updates those nanoScroller properties that
are related to current scrollbar position.
@method updateScrollValues
@private
*/
NanoScroll.prototype.updateScrollValues = function() {
var content;
content = this.content;
this.maxScrollTop = content.scrollHeight - content.clientHeight;
this.contentScrollTop = content.scrollTop;
if (!this.iOSNativeScrolling) {
this.maxSliderTop = this.paneHeight - this.sliderHeight;
this.sliderTop = this.contentScrollTop * this.maxSliderTop / this.maxScrollTop;
}
};
/**
Creates event related methods
@method createEvents
@private
*/
NanoScroll.prototype.createEvents = function() {
var _this = this;
this.events = {
down: function(e) {
_this.isBeingDragged = true;
_this.offsetY = e.pageY - _this.slider.offset().top;
_this.pane.addClass('active');
_this.doc.bind(MOUSEMOVE, _this.events[DRAG]).bind(MOUSEUP, _this.events[UP]);
return false;
},
drag: function(e) {
_this.sliderY = e.pageY - _this.$el.offset().top - _this.offsetY;
_this.scroll();
_this.updateScrollValues();
if (_this.contentScrollTop >= _this.maxScrollTop) {
_this.$el.trigger('scrollend');
} else if (_this.contentScrollTop === 0) {
_this.$el.trigger('scrolltop');
}
return false;
},
up: function(e) {
_this.isBeingDragged = false;
_this.pane.removeClass('active');
_this.doc.unbind(MOUSEMOVE, _this.events[DRAG]).unbind(MOUSEUP, _this.events[UP]);
return false;
},
resize: function(e) {
_this.reset();
},
panedown: function(e) {
_this.sliderY = (e.offsetY || e.originalEvent.layerY) - (_this.sliderHeight * 0.5);
_this.scroll();
_this.events.down(e);
return false;
},
scroll: function(e) {
if (_this.isBeingDragged) {
return;
}
_this.updateScrollValues();
if (!_this.iOSNativeScrolling) {
_this.sliderY = _this.sliderTop;
_this.slider.css({
top: _this.sliderTop
});
}
if (e == null) {
return;
}
if (_this.contentScrollTop >= _this.maxScrollTop) {
if (_this.options.preventPageScrolling) {
_this.preventScrolling(e, DOWN);
}
_this.$el.trigger('scrollend');
} else if (_this.contentScrollTop === 0) {
if (_this.options.preventPageScrolling) {
_this.preventScrolling(e, UP);
}
_this.$el.trigger('scrolltop');
}
},
wheel: function(e) {
if (e == null) {
return;
}
_this.sliderY += -e.wheelDeltaY || -e.delta;
_this.scroll();
return false;
}
};
};
/**
Adds event listeners with jQuery.
@method addEvents
@private
*/
NanoScroll.prototype.addEvents = function() {
var events;
this.removeEvents();
events = this.events;
if (!this.options.disableResize) {
this.win.bind(RESIZE, events[RESIZE]);
}
if (!this.iOSNativeScrolling) {
this.slider.bind(MOUSEDOWN, events[DOWN]);
this.pane.bind(MOUSEDOWN, events[PANEDOWN]).bind("" + MOUSEWHEEL + " " + DOMSCROLL, events[WHEEL]);
}
this.$content.bind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
};
/**
Removes event listeners with jQuery.
@method removeEvents
@private
*/
NanoScroll.prototype.removeEvents = function() {
var events;
events = this.events;
this.win.unbind(RESIZE, events[RESIZE]);
if (!this.iOSNativeScrolling) {
this.slider.unbind();
this.pane.unbind();
}
this.$content.unbind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]);
};
/**
Generates nanoScroller's scrollbar and elements for it.
@method generate
@chainable
@private
*/
NanoScroll.prototype.generate = function() {
var contentClass, cssRule, options, paneClass, sliderClass;
options = this.options;
paneClass = options.paneClass, sliderClass = options.sliderClass, contentClass = options.contentClass;
if (!this.$el.find("" + paneClass).length && !this.$el.find("" + sliderClass).length) {
this.$el.append("<div class=\"" + paneClass + "\"><div class=\"" + sliderClass + "\" /></div>");
}
this.pane = this.$el.children("." + paneClass);
this.slider = this.pane.find("." + sliderClass);
if (BROWSER_SCROLLBAR_WIDTH) {
cssRule = this.$el.css('direction') === 'rtl' ? {
left: -BROWSER_SCROLLBAR_WIDTH
} : {
right: -BROWSER_SCROLLBAR_WIDTH
};
this.$el.addClass('has-scrollbar');
}
if (cssRule != null) {
this.$content.css(cssRule);
}
return this;
};
/**
@method restore
@private
*/
NanoScroll.prototype.restore = function() {
this.stopped = false;
this.pane.show();
this.addEvents();
};
/**
Resets nanoScroller's scrollbar.
@method reset
@chainable
@example
$(".nano").nanoScroller();
*/
NanoScroll.prototype.reset = function() {
var content, contentHeight, contentStyle, contentStyleOverflowY, paneBottom, paneHeight, paneOuterHeight, paneTop, sliderHeight;
if (this.iOSNativeScrolling) {
this.contentHeight = this.content.scrollHeight;
return;
}
if (!this.$el.find("." + this.options.paneClass).length) {
this.generate().stop();
}
if (this.stopped) {
this.restore();
}
content = this.content;
contentStyle = content.style;
contentStyleOverflowY = contentStyle.overflowY;
if (BROWSER_IS_IE7) {
this.$content.css({
height: this.$content.height()
});
}
contentHeight = content.scrollHeight + BROWSER_SCROLLBAR_WIDTH;
paneHeight = this.pane.outerHeight();
paneTop = parseInt(this.pane.css('top'), 10);
paneBottom = parseInt(this.pane.css('bottom'), 10);
paneOuterHeight = paneHeight + paneTop + paneBottom;
sliderHeight = Math.round(paneOuterHeight / contentHeight * paneOuterHeight);
if (sliderHeight < this.options.sliderMinHeight) {
sliderHeight = this.options.sliderMinHeight;
} else if ((this.options.sliderMaxHeight != null) && sliderHeight > this.options.sliderMaxHeight) {
sliderHeight = this.options.sliderMaxHeight;
}
if (contentStyleOverflowY === SCROLL && contentStyle.overflowX !== SCROLL) {
sliderHeight += BROWSER_SCROLLBAR_WIDTH;
}
this.maxSliderTop = paneOuterHeight - sliderHeight;
this.contentHeight = contentHeight;
this.paneHeight = paneHeight;
this.paneOuterHeight = paneOuterHeight;
this.sliderHeight = sliderHeight;
this.slider.height(sliderHeight);
this.events.scroll();
this.pane.show();
this.isActive = true;
if ((content.scrollHeight === content.clientHeight) || (this.pane.outerHeight(true) >= content.scrollHeight && contentStyleOverflowY !== SCROLL)) {
this.pane.hide();
this.isActive = false;
} else if (this.el.clientHeight === content.scrollHeight && contentStyleOverflowY === SCROLL) {
this.slider.hide();
} else {
this.slider.show();
}
this.pane.css({
opacity: (this.options.alwaysVisible ? 1 : ''),
visibility: (this.options.alwaysVisible ? 'visible' : '')
});
return this;
};
/**
@method scroll
@private
@example
$(".nano").nanoScroller({ scroll: 'top' });
*/
NanoScroll.prototype.scroll = function() {
if (!this.isActive) {
return;
}
this.sliderY = Math.max(0, this.sliderY);
this.sliderY = Math.min(this.maxSliderTop, this.sliderY);
this.$content.scrollTop((this.paneHeight - this.contentHeight + BROWSER_SCROLLBAR_WIDTH) * this.sliderY / this.maxSliderTop * -1);
if (!this.iOSNativeScrolling) {
this.slider.css({
top: this.sliderY
});
}
return this;
};
/**
Scroll at the bottom with an offset value
@method scrollBottom
@param offsetY {Number}
@chainable
@example
$(".nano").nanoScroller({ scrollBottom: value });
*/
NanoScroll.prototype.scrollBottom = function(offsetY) {
if (!this.isActive) {
return;
}
this.reset();
this.$content.scrollTop(this.contentHeight - this.$content.height() - offsetY).trigger(MOUSEWHEEL);
return this;
};
/**
Scroll at the top with an offset value
@method scrollTop
@param offsetY {Number}
@chainable
@example
$(".nano").nanoScroller({ scrollTop: value });
*/
NanoScroll.prototype.scrollTop = function(offsetY) {
if (!this.isActive) {
return;
}
this.reset();
this.$content.scrollTop(+offsetY).trigger(MOUSEWHEEL);
return this;
};
/**
Scroll to an element
@method scrollTo
@param node {Node} A node to scroll to.
@chainable
@example
$(".nano").nanoScroller({ scrollTo: $('#a_node') });
*/
NanoScroll.prototype.scrollTo = function(node) {
if (!this.isActive) {
return;
}
this.reset();
this.scrollTop($(node).get(0).offsetTop);
return this;
};
/**
To stop the operation.
This option will tell the plugin to disable all event bindings and hide the gadget scrollbar from the UI.
@method stop
@chainable
@example
$(".nano").nanoScroller({ stop: true });
*/
NanoScroll.prototype.stop = function() {
this.stopped = true;
this.removeEvents();
this.pane.hide();
return this;
};
/**
To flash the scrollbar gadget for an amount of time defined in plugin settings (defaults to 1,5s).
Useful if you want to show the user (e.g. on pageload) that there is more content waiting for him.
@method flash
@chainable
@example
$(".nano").nanoScroller({ flash: true });
*/
NanoScroll.prototype.flash = function() {
var _this = this;
if (!this.isActive) {
return;
}
this.reset();
this.pane.addClass('flashed');
setTimeout(function() {
_this.pane.removeClass('flashed');
}, this.options.flashDelay);
return this;
};
return NanoScroll;
})();
$.fn.nanoScroller = function(settings) {
return this.each(function() {
var options, scrollbar;
if (!(scrollbar = this.nanoscroller)) {
options = $.extend({}, defaults, settings);
this.nanoscroller = scrollbar = new NanoScroll(this, options);
}
if (settings && typeof settings === "object") {
$.extend(scrollbar.options, settings);
if (settings.scrollBottom) {
return scrollbar.scrollBottom(settings.scrollBottom);
}
if (settings.scrollTop) {
return scrollbar.scrollTop(settings.scrollTop);
}
if (settings.scrollTo) {
return scrollbar.scrollTo(settings.scrollTo);
}
if (settings.scroll === 'bottom') {
return scrollbar.scrollBottom(0);
}
if (settings.scroll === 'top') {
return scrollbar.scrollTop(0);
}
if (settings.scroll && settings.scroll instanceof $) {
return scrollbar.scrollTo(settings.scroll);
}
if (settings.stop) {
return scrollbar.stop();
}
if (settings.flash) {
return scrollbar.flash();
}
}
return scrollbar.reset();
});
};
})(jQuery, window, document);

View File

@ -0,0 +1,25 @@
$(document).ready(function() {
$(".select_user_modal").on('click', function(){
var ids = [];
var users = $(this).siblings('#selected_users').children('span.selected_user');
users.each(function(i) {
ids.push(users.eq(i).attr('user_id'));
});
$("#main-wrap").after("<span id='select_user'></span>");
$.ajax({
type: 'GET',
url: $(this).attr("rel"),
dataType: 'script',
data: {field: $(this).attr("field"), ids: ids},
success: function (msg) {
$("#select_user_modal").modal('show'); },
error: function(){
alert("ERROR");
}
});
return false;
});
$(document).on('click', ".remove_user", function(){
$(this).parent().remove();
});
});

View File

@ -9,7 +9,7 @@ function load_tinymce() {
// Theme options
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,bullist,numlist,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,fullscreen",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,fullscreen,|,template",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
@ -20,7 +20,7 @@ function load_tinymce() {
skin_variant : "silver",
font_size_style_values : "xx-small,x-small,small,medium,large,x-large,xx-large",
// Drop lists for link/image/media/template dialogs
template_external_list_url : "js/template_list.js",
template_external_list_url : "/tinymce/lists/template_list.js",
// external_link_list_url : "js/link_list.js",
// external_image_list_url : "js/image_list.js",
// media_external_list_url : "js/media_list.js"

View File

@ -0,0 +1,230 @@
/* Member Filter */
#select_user #select_user_modal.modal {
width: 80%;
margin-left: -40%;
}
#select_user #select_user_modal .modal-body {
max-height: 425px;
}
#select_user #select_user_modal .modal-body form {
margin-bottom: 0px;
}
#select_user #select_user_modal .modal-body form fieldset {
min-height: 360px;
}
#select_user #select_user_modal .modal-body .radio.inline,
#select_user #select_user_modal .modal-body .checkbox.inline {
display: inline-block;
padding-top: 5px;
margin-bottom: 0;
vertical-align: middle;
min-width: 100px;
margin-left: 0;
}
#select_user #select_user_modal .modal-body .form-actions {
margin: 20px 0 0;
padding: 10px 0 0;
background-color: transparent;
text-align: right;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano {
width: 160px;
min-height: 425px;
float: left;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano .pane {
right: 6px;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs {
width: 140px;
float: left;
margin-bottom: 0;
margin-right: 0;
border-right: 1px solid #ddd;
border-bottom: none;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li {
float: none;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a {
min-width: 74px;
margin-right: 0;
margin-bottom: 3px;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a {
margin-right: -1px;
-webkit-border-radius: 4px 0 0 4px;
-moz-border-radius: 4px 0 0 4px;
border-radius: 4px 0 0 4px;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs > li > a:hover {
border-color: #eeeeee #dddddd #eeeeee #eeeeee;
}
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs .active > a,
#select_user #select_user_modal .modal-body .tabs-left > .nano > .content > .nav-tabs .active > a:hover {
border-color: #ddd transparent #ddd #ddd;
*border-right-color: #ffffff;
}
#select_user #select_user_modal .member-filter-options {
float: left;
display: inline-block;
width: 175px;
min-height: 425px;
margin-right: 10px;
padding: 0 10px 0 0;
}
#select_user #select_user_modal .member-filter-options select {
width: 165px;
}
#select_user #select_user_modal .member-filter-options .btn {
display: block;
}
#select_user #select_user_modal .member-filter-result {
padding-left: 15px;
min-height: 360px;
width: auto;
}
/* Check Box Card */
.checkbox-card {
margin: 0;
}
.checkbox-card li {
position: relative;
list-style: none;
color: #FFFFFF;
width: 180px;
height: 40px;
margin: 0 10px 10px 0;
float: left;
display: inline-block;
background-color: #cccccc;
overflow: hidden;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-webkit-transition: all .2s linear;
-moz-transition: all .2s linear;
-o-transition: all .2s linear;
transition: all .2s linear;
}
.checkbox-card li.mark {
width: 0;
height: 0;
padding: 0;
margin: 0;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0);
opacity: 0;
visibility: hidden;
}
.checkbox-card li:hover {
background-color: #0088cc;
}
.checkbox-card li:after {
content: "";
display: block;
clear: both;
height: 0;
visibility: hidden;
}
.checkbox-card li.active:before {
-webkit-text-size-adjust : none;
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
color: #FFF;
text-decoration: inherit;
content: "\f00c";
position: absolute;
right: 0px;
top: 0px;
line-height: 14px;
text-indent: 10px;
font-size: 10px;
width: 0px;
height: 0px;
border-style: solid;
border-width: 0 22px 22px 0;
border-color: transparent #51a351 transparent transparent;
}
.checkbox-card li.active label {
}
.checkbox-card li label {
margin-bottom: 0px;
overflow: hidden;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
.checkbox-card li input {
opacity: 0;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
margin: 0;
z-index: 10;
}
.checkbox-card li label span {
-webkit-text-size-adjust : none;
font-size: 10px;
display: block;
width: 130px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: #666666;
margin-top: -3px;
}
.checkbox-card li:hover label span,
.checkbox-card li:hover label span.user-name {
color: #FFFFFF;
}
.checkbox-card li label span.user-name {
font-size: 12px;
color: #363636;
padding: 2px 0 0;
margin-top: 0;
}
.checkbox-card li .user-pic {
float: left;
margin-right: 5px;
width: 40px;
height: 40px;
}
#selected_users .selected_user {
display: block;
margin-bottom: 5px;
}
#selected_users .selected_user .remove_user {
font-size: 15px;
}
/*
.promoter {
border-color: #CCCCCC;
border-style: solid;
border-width: 0 1px;
padding: 0 10px 5px 10px;
}
.promoter > div {
border-bottom: 1px solid #CCCCCC;
}
.promoter > div:after {
content: "";
clear: both;
display: block;
visibility: hidden;
}
.promoter > div > span {
display: block;
margin-left: 70px;
padding-bottom: 5px;
}
.promoter p {
width: 70px;
float: left;
text-align:right;
}*/

View File

@ -55,9 +55,9 @@
width:100%;
}
#orbit-bar .orbit-logo .brand {
background:url(<%= asset_path 'orbit-bar.png' %>) no-repeat -162px -5px;
text-indent:-9999px;
padding:5px 20px 4px;
background: url(<%= asset_path 'ga-logo.png' %>) no-repeat center center;
text-indent: -9999px;
padding: 5px 20px 4px;
}
#orbit-bar .orbit-logo .brand:hover {
background-color:#009ddc;

View File

@ -1,5 +1,7 @@
/*style*/
* {
outline: none;
}
@font-face{
font-family: 'WebSymbolsRegular';
src: url(<%= asset_path 'websymbols-regular-webfont.eot' %>);

View File

@ -70,4 +70,30 @@ class Admin::MemberSelectsController < OrbitBackendController
end
def select_members
selected_users = User.find(params[:ids]) rescue []
@field = params[:field]
roles = Role.all
@sorted_users = roles.inject({}) do |users, role|
users[role] = role.users.where(:email.not => /guest|rulingcom/) - selected_users
users
end
end
def set_roles
roles = Role.find(params[:role_ids]) rescue []
@field = params[:field]
@users = roles.inject([]) do |users, role|
users += role.users.where(:email.not => /guest|rulingcom/).entries
users
end
render 'admin/member_selects/update_selected_users'
end
def set_users
@users = User.find(params[:user_ids]) rescue []
@field = params[:field]
render 'admin/member_selects/update_selected_users'
end
end

View File

@ -0,0 +1,36 @@
class SamlLoginsController < ApplicationController
require "net/http"
require "uri"
require 'rexml/document'
include REXML
def index
if params[:wa] == "wsignoutcleanup1.0" #logout
redirect_to :root
else #login
@wresult = params[:wresult]
@wctx = params[:wctx]
@main_url = LIST[:sites][@wctx]['url']
@main_public_key = LIST[:sites][@wctx]['key']
@doc = REXML::Document.new @wresult
@main_public_key = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzKawlFWAMzA/uV/kcewd\nmtj8PcqxosmnSh7ZzJ0DumG2ieeP9oDBicqbqIEaeJVvrRzYJD2a+u8x5KKMKB8J\nHbMUpCBFlIpkDMjU/oZVMcYT9pcH51QWNvCgHG7prVykSGFz1JRvjSP6cwuZKBFd\nFFneOViETqoMIO1DbRLXsGfPvMOJY9C1xDwv1dLv0Wbj7M9N6eNz06a50bu3I4gl\nMumxWnZUabXL3G62S/Si4NM7J2jOUnkEOxJWOhcAX/iiqS9T8AHu84um2+mLQpfB\nJJFFIWCIAtU78VnIN5JSWwjFU5TsiSyCFYpGXKxUFD25cFmt3SfG0gwmrFis5Pdn\nhwIDAQAB\n-----END PUBLIC KEY-----\n"
public_key = OpenSSL::PKey::RSA.new(@main_public_key)
encrypted_data = public_key.public_encrypt(@doc.elements["//saml:AttributeValue"].text)
redirect_to "http://#{@main_url}/user_login?" + { :wresult => encrypted_data }.to_param
end
end
end

View File

@ -0,0 +1,40 @@
# encoding: utf-8
class SessionsController < Devise::SessionsController
prepend_before_filter :require_no_authentication, :only => [ :new, :create ]
def create
@site = Site.first
private_key = OpenSSL::PKey::RSA.new(@site.private_key)
wresult = private_key.private_decrypt(request.params['wresult'])
@ids = wresult.split("@")
login_uid = @ids[0]
resource = User.first(conditions:{user_id: login_uid})
if !resource.blank?
resource_name = resource.class.to_s.downcase
sign_in(resource_name, resource)
session[:user_id_type] = "myntu"
redirect_to after_sign_in_path_for(resource)
else
flash[:error] = "很抱歉,您無此權限或帳號登入本站,請洽本站管理員<br />Sorry, you don't have the account or authority to login. Please contact the website administrator."
redirect_to :root
end
end
def destroy
@user_id_type = session[:user_id_type]
sign_out
if @user_id_type == "myntu"
redirect_to "https://adfs.ntu.edu.tw/adfs/ls/?wa=wsignout1.0&wreply=https://galogin.ntu.edu.tw"
else
redirect_to root_path
end
end
end

View File

@ -303,7 +303,7 @@ module ApplicationHelper
# NTU link
def get_link(site_number)
"http://#{request.host}:2#{site_number}00"
"http://#{site_number}.#{request.domain(3)}"
end
def sortable(column, title = nil, options = {})

View File

@ -0,0 +1,7 @@
class GetAnnouncementFromRss
@queue = :high
def self.perform()
%x(ruby "#{Rails.root}/lib/rss_ntu_job.rb")
end
end

View File

@ -10,7 +10,7 @@ class Role < Attribute
field :title, localize: true
has_many :sub_roles, :autosave => true, :dependent => :destroy
has_many :users
has_and_belongs_to_many :users
# has_many :statuses, :autosave => true, :dependent => :destroy
# has_many :attribute_fields, :autosave => true, :dependent => :destroy
has_many :role_statuses, :autosave => true, :dependent => :destroy

View File

@ -0,0 +1,86 @@
<div id="select_user_modal" class="modal hide fade">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3><%= t('list.user') %></h3>
</div>
<div class="modal-body">
<div class="tabbable tabs-left">
<div class="nano">
<div class="content">
<ul class="nav nav-tabs">
<li class="active"><a href="#all" data-toggle="tab"><%= t('list.role') %></a></li>
<% @sorted_users.each_key do |role| %>
<li class=""><a href="#r_<%= role.id %>" data-toggle="tab"><%= role.title %></a></li>
<% end %>
</ul>
</div>
</div>
<div class="tab-content">
<div class="tab-pane fade in active" id="all">
<%= form_tag set_roles_admin_member_selects_path(field: @field), remote: true do %>
<fieldset>
<% @sorted_users.each_key do |role| %>
<label class="checkbox inline">
<%= check_box_tag 'role_ids[]', role.id , false %> <%= role.title %>
</label>
<% end %>
</fieldset>
<div class="form-actions">
<button type="button" class="btn" data-dismiss="modal"><%= t(:cancel) %></button>
<%= submit_tag t(:submit), class: "btn btn-primary" %>
</div>
<% end %>
</div>
<% @sorted_users.each do |role, users| %>
<div class="tab-pane fade" id="r_<%= role.id %>">
<%= form_tag set_users_admin_member_selects_path(field: @field), remote: true do %>
<fieldset class="clearfix">
<div class="member-filter-result nano">
<div class="content">
<ul class="checkbox-card clearfix">
<% users.each do |user| %>
<li>
<label>
<%= image_tag (user.avatar.file ? user.avatar : "menber-pic.png"), class: "user-pic" %>
<span class="user-name"><%= user.name %></span>
</label>
<%= check_box_tag 'user_ids[]', user.id , false %>
</li>
<% end %>
</ul>
</div>
</div>
<div class="form-actions condition">
<button type="button" class="btn" data-dismiss="modal"><%= t(:cancel) %></button>
<%= submit_tag t(:submit), class: "btn btn-primary" %>
</div>
</fieldset>
<% end %>
</div>
<% end %>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(".modal").on("hidden", function () {
$("#select_user").remove();
$('#select_user_modal').on('shown', function() {
$(this).find('.nano').nanoScroller({ scrollTop: 0, iOSNativeScrolling: true });
$(this).find('.checkbox-card > li').cardCheck({
check: $(this).find('.checkbox-card > li input[type="checkbox"]'),
});
});
});
$('#select_user_modal').on('shown', function() {
$('#select_user_modal').off('shown')
$(this).find('.nano').nanoScroller({ scrollTop: 0, iOSNativeScrolling: true });
$(this).find('.checkbox-card > li').cardCheck({
check: $(this).find('.checkbox-card > li input[type="checkbox"]'),
});
});
});
</script>

View File

@ -0,0 +1,14 @@
<% unless users.blank? %>
<div class="promoter-block">
<p class="promoter-title"><%= t(:promoter) %></p>
<ul>
<% users.each do |user| %>
<li class="promoter">
<p>
<%= link_to user.name, "mailto:#{user.email}", class: "promoter-name" %> / <span class="promoter-phone"><%= user.office_tel %></span>
</p>
</li>
<% end %>
</ul>
</div>
<% end %>

View File

@ -0,0 +1,16 @@
<% content_for :page_specific_javascript do -%>
<%= javascript_include_tag "member-selection" %>
<%= javascript_include_tag "lib/jquery.nanoscroller" %>
<%= javascript_include_tag "lib/checkbox.card" %>
<% end -%>
<% content_for :page_specific_css do -%>
<%= stylesheet_link_tag "member_select" %>
<% end %>
<div>
<div id="selected_users">
<%= render partial: 'admin/member_selects/user', collection: users, locals: {field: field} %>
<%= hidden_field_tag field %>
</div>
<%= link_to t(:add), '#', class: 'btn btn-primary btn-small select_user_modal', rel: select_members_admin_member_selects_path, field: field %>
</div>

View File

@ -0,0 +1,5 @@
<span class="alert alert-info selected_user" user_id="<%= user.id %>">
<%= user.name %>
<%= hidden_field_tag field, user.id %>
<%= content_tag :span, '×', class: 'close remove_user' %>
</span>

View File

@ -0,0 +1,2 @@
$("#select_user").html("<%= j render partial: 'admin/member_selects/modal_select', locals: {field: 'bulletin[user_ids][]'} %>");
$("#select_user_modal").modal();

View File

@ -0,0 +1,2 @@
$("#selected_users").append("<%= j render partial: 'user', collection: @users, locals: {field: @field} %>");
$("#select_user_modal").modal('hide');

View File

@ -17,4 +17,4 @@
<%= render :partial=> "widget_ext_options" %>
</div>
</div>
<% end %>
<% end %>

View File

@ -9,15 +9,20 @@
<%= content_tag :span, msg, :class => [key, "notice label label-warning"] %>
<% end %>
<p class="alert hide">You need to sign in or sign up before continuing.</p>
<% @request_hosts = request.host_with_port.split(".") %>
<a href="https://adfs.ntu.edu.tw/adfs/ls/?wa=wsignin1.0&wtrealm=https://galogin.ntu.edu.tw/saml_login&wctx=<%= @request_hosts[0] %>" class="btn btn-primary" style="width: 310px;margin-top: 10px;">使用計中帳號登入</a>
<p style="margin: 40px 0 20px; position: relative; border-bottom: 1px solid #DDD;">
<span style="position: absolute; width: 140px; left: 50%; margin-left: -70px; font-size: 14px; top: -9px; background-color: #fff; text-align: center;">或使用本站帳號登入</span>
</p>
<div class="main">
<div class="control-group clear">
<%= f.label :user_id ,t("users.user_id")%>
<%= f.text_field :user_id, :placeholder => t("users.user_id"), :style => "width: 330px;" %>
<%= f.text_field :user_id, :placeholder => t("users.user_id"), :style => "width: 326px;" %>
<span class="help-inline">Please correct the error</span>
</div>
<div class="control-group clear">
<%= f.label :password,t("password") %>
<%= f.password_field :password, :placeholder => t(:dots), :style => "width: 330px;" %>
<%= f.password_field :password, :placeholder => t(:dots), :style => "width: 326px;" %>
<span class="help-inline">Please correct the error</span>
<%= link_to t(:forgot_password), new_user_password_path, :class => 'pull-right forgot hide' %>
</div>

View File

@ -10,19 +10,10 @@
</div>
<ul class="nav">
<li><a href="<%= root_path %>" data-icons="&#xe022;"></a></li>
<li><a href="<%= desktop_path %>" data-icons="&#xe060;"></a></li>
<!-- <li><a href="<%#= desktop_path %>" data-icons="&#xe060;"></a></li> -->
</ul>
<ul class="nav pull-right">
<!--
<li class="dropdown">
<a class="dropdown-toggle" data-icons="&#xe02d;" href="#" data-toggle="dropdown"></a>
<ul class="dropdown-menu">
<% #t('ntu.site_names').each do |site| %>
<li><%#= link_to site[1], get_link(site[0]) %></li>
<%# end %>
</ul>
</li>
-->
<li class="search clear" title="<%= t :search_google %>">
<a class="orbit-bar-search" href="#" data-icons="&#xe024;"></a>
<form class="navbar-search" method="get" action="http://www.google.com/custom">
@ -34,6 +25,17 @@
<input type='hidden' name='sitesearch' value='<%= @site.search["sitesearch"] rescue '' %>'>
<%= text_field_tag 'q','',{:class => "search-query span3",:placeholder=> t(:search_google) ,:disabled=> ((@site.search["sitesearch"] || @site.search["domains"] ).blank? rescue true)}%>
</form>
<li class="dropdown language">
<a class="dropdown-toggle orbit-bar-language" data-icons="&#xe02d;" href="#" data-toggle="dropdown"></a>
<ul class="dropdown-menu language-menu">
<% t('ntu.site_names').each do |site| %>
<li><%= link_to site[1], get_link(site[0]) %></li>
<% end %>
</ul>
</li>
</li>
<li class="dropdown language">
<a class="dropdown-toggle orbit-bar-language" href="#" data-toggle="dropdown" data-icons="&#xe054;"></a>
@ -53,7 +55,7 @@
<ul class="dropdown-menu account-menu">
<!-- <li><%= link_to content_tag(:i, nil, :class => 'icons-tools') + ' ' + t(:account_setting), desktop_path+"#settings-account" %></li> -->
<!-- <li><%= link_to content_tag(:i, nil, :class => 'icons-screen') + ' ' + t(:desktop), desktop_path %></li> -->
<li><%= link_to content_tag(:i, nil, :class => 'icons-logout') + ' ' + t(:logout), destroy_user_session_path %></li>
<li><%= link_to content_tag(:i, nil, :class => 'icons-logout') + ' ' + t(:logout), user_logout_path %></li>
<li class="divider"></li>
<li>
<a href="#">
@ -68,7 +70,13 @@
<a class="dropdown-toggle orbit-bar-member" href="#" data-icons="&#xe076;"></a>
<div class="dropdown-menu">
<ul class="log">
<li class="title hide"></li>
<li style="margin-top: 30px;">
<% @request_hosts = request.host_with_port.split(".") %>
<a class="btn btn-primary" href="https://adfs.ntu.edu.tw/adfs/ls/?wa=wsignin1.0&wtrealm=https://galogin.ntu.edu.tw/saml_login&wctx=<%= @request_hosts[0] %>" style="padding: 3px 0;color: #fff;">使用計中帳號登入</a>
</li>
<li class="divider" style="margin: 40px 0 0;">
<span style="width: 140px;left: 50%;margin-left: -70px;font-size: 14px;">或使用本站帳號登入</span>
</li>
<%= form_for :user, :url => user_session_path do |f| %>
<li>

View File

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%= @title || APP_CONFIG['orbit'] %></title>
<link rel="shortcut icon" href="<%= asset_path "ncculogo.ico" %>">
<link rel="shortcut icon" href="<%= asset_path "favicon.ico" %>">
<%= yield :page_specific_link %>
<%= stylesheet_link_tag "new_admin" %>
<%= javascript_include_tag "new_admin" %>

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<title><%= @title || APP_CONFIG['orbit'] %></title>
<link rel="shortcut icon" href="<%= asset_path "ncculogo.ico" %>">
<link rel="shortcut icon" href="<%= asset_path "favicon.ico" %>">
<!--[if lt IE 9]>
<%= javascript_include_tag "html5" %>
<![endif]-->

View File

@ -1,9 +1,22 @@
<!DOCTYPE HTML>
<html class="<%= I18n.locale.to_s %>">
<head>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36964512-1']);
_gaq.push(['_setDomainName', 'ga.ntu.edu.tw']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<meta charset="utf-8">
<%= page_title(@item).html_safe %>
<link rel="shortcut icon" href="<%= asset_path "ncculogo.ico" %>">
<link rel="shortcut icon" href="<%= asset_path "favicon.ico" %>">
<%= page_metas(@item).html_safe %>
<!--[if lt IE 9]>
<%= javascript_include_tag "html5" %>

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<%= page_title(@item).html_safe %>
<link rel="shortcut icon" href="<%= asset_path "ncculogo.ico" %>">
<link rel="shortcut icon" href="<%= asset_path "favicon.ico" %>">
<%= page_metas(@item).html_safe %>
<!--[if lt IE 9]>
<%= javascript_include_tag "html5" %>

View File

@ -3,9 +3,7 @@
<% end %>
<ul>
<li>總機電話:<a href="tel:+886229393091">02-29393091</a></li>
<li>傳真02-29379611</li>
<li>緊急重大事件通聯窗口:校內分機 66119、66110</li>
<li>總值日室:<a href="tel:+88229387132">02-29387132</a></li>
<li>駐警衛室:<a href="tel:+88229387129">02-29387129</a></li>
<li>總務處電話:<a href="tel:+886229393091">02-29393091</a></li>
<li>總務處傳真02-29379611</li>
<li>總務處單一窗口 李梅森專員:<a href="tel:+886233662233">02-33662233</a></li>
</ul>

View File

@ -5,6 +5,6 @@
<div id='map_canvas'></div>
<script type='text/javascript'>
var $map_center = "24.987449, 121.576117"
var $map_center = "25.015205, 121.535491"
var $map_zoom = 17
</script>

View File

@ -335,6 +335,7 @@ en:
posted_by: Posted by
preview: Preview
profile: Profile
promoter: Promoter
publications: Publications
purchase: Purchase
quantity: Quantity

View File

@ -9,5 +9,5 @@ en:
home: Home
language: Language
location: Location
location_description: '<h3>This University</h3>No.101,Sec. 2, Jiafeng S Road, Zhubei City, Hsinchu County 302, Taiwan'
location_description: '<h3>OFFICE OF GENERAL AFFAIRS, NTU</h3>No. 1, Sec. 4, Roosevelt Road, Taipei, 10617 Taiwan (R.O.C)'
page: Page

View File

@ -9,5 +9,5 @@ zh_tw:
home: 首頁
language: 語言
location: 地理位置
location_description: '<h3>本大學</h3>302新竹縣竹北市嘉豐南路二段101號'
location_description: '<h3>臺灣大學總務處 版權所有</h3>10617 臺北市大安區羅斯福路四段一號'
page: 頁面

17
config/locales/ntu.en.yml Normal file
View File

@ -0,0 +1,17 @@
en:
ntu:
rss_origin: Back to NTU Announcements
site_names:
"www": "Dean of General Affairs"
"sec": "Office of the Dean and Secretariat"
"doc": "Documentation Division"
"general": "General Service Division"
"property": "Property Management Division"
"construction": "Construction and Maintenance Division"
"cashier": "Cashier Division"
"procurement": "Procurement Division"
"fss": "Facilities Service Division"
"police": "Campus Security"
"social": "General Affairs Division, College of Social Science"
"medicine": "General Service Division, College of Medicine"

View File

@ -0,0 +1,17 @@
zh_tw:
ntu:
rss_origin: 回臺大校園公佈欄
site_names:
"www": "總務處"
"sec": "總務長室暨總務處秘書室"
"doc": "文書組"
"general": "事務組"
"property": "保管組"
"construction": "營繕組"
"cashier": "出納組"
"procurement": "採購組"
"fss": "經營管理組"
"police": "駐警隊"
"social": "社科院總務分處"
"medicine": "醫學院總務分處"

View File

@ -336,6 +336,7 @@ zh_tw:
posted_by: 張貼人
preview: 預覽
profile: 基本資料
promoter: 承辦人
publications: 著作
purchase: 購買
quantity: 數量

View File

@ -11,7 +11,7 @@ backup_server:
description: BackupServer and remove old backups
update_tag_cloud:
cron: 0 0 [0,12] * * *
cron: 0 30 2 * * *
class: UpdateTagCloud
args:
description: UpdateTagCloud
@ -27,3 +27,9 @@ email_cron:
class: EmailCron
args:
description: EmailCron
get_announcement_from_rss:
cron: 0 0 [2,12] * * *
class: GetAnnouncementFromRss
args:
description: Loop through the announcement RSS until 24h ago

View File

@ -7,6 +7,13 @@ Orbit::Application.routes.draw do
match "/users_passwd" => "desktop/registrations#update", :as => :users_passwd, :via => :put
end
devise_scope :user do
get 'user_login' => 'sessions#create'
match 'user_logout' => 'sessions#destroy'
end
match "saml_login" => 'saml_logins#index'
mount Resque::Server, :at => "/admin/resque"
mount Rack::GridFS::Endpoint.new(:db => Mongoid.database,:lookup=>:path), :at => "gridfs"
@ -188,6 +195,11 @@ Orbit::Application.routes.draw do
resources :member_selects do
match 'member_select_search' => "member_selects#member_select_search" ,:as => :member_select_search,:via => "post"
match 'member_select_add' => "member_selects#member_select_add" ,:as => :member_select_add,:via => "post"
collection do
get 'select_members'
post 'set_roles'
post 'set_users'
end
end
match 'module_store' => 'module_store#index'

View File

@ -0,0 +1,144 @@
# encoding : utf-8
# Usage ===============
#
# ARGV[0] = folder path of xml files
# ARGV[1] = folder path of files
#
#======================
require 'mongo'
require 'nokogiri'
include Mongo
CSV_PATH = ARGV[0]
FILE_PATH = ARGV[1]
FIELDS = %w[title file createdate modifydate createuser modifyuser]
DB_BASE_NAME = "production"
TABLE = {
"0" => ["gaTaco", "ntuga"],
"1" => ["fdLai", "fdhome"],
"5" => ["prLin", "property01"],
"3" => ["gsTien", "ckh", "general01", "lynn"],
"10" => ["cmChen", "construction01", "allen", "enAmeliaxu", "energy"],
# "2" => ["caLin", "cashier01"],
"6" => ["pcAmyok", "purchasing01", "purchasing02"],
"7" => ["fmHsyu", "ntufss"],
"4" => ["soChang", "social01"],
"8" => ["meJune", "medicine01"],
"9" => ["plKoa", "police"]
}
which_site = {}
data = []
Dir.foreach(ARGV[0]) do |file|
if file =~ /\w\.\w/
doc = Nokogiri::XML(File.open(File.join(ARGV[0], file)))
doc.xpath("//row").each { |row|
xml_fields = row.children.map{ |row| [row.name, row.content] }
fields = FIELDS.inject([]) do |fields, field|
xml_fields.each do |xf|
if xf[0].include?(field)
fields << xf[1]
break
end
end
fields
end
data << fields + [File.basename(file, '.xml')]
}
data.each do |d|
title, file, c_time, m_time, creator, modifier, category = d
if file =~ /\w\.\w/
file = File.join(File.join(ARGV[1], file))
site = ""
TABLE.each do |key, value|
if value.include? modifier
site = key
break
elsif value.include? creator
site = key
break
end
end
site = "0" if site.empty?
if which_site[site]
if which_site[site][category]
which_site[site][category] += [[title, file, c_time, m_time]]
else
which_site[site][category] = [[title, file, c_time, m_time]]
end
else
which_site[site] = {category => [[title, file, c_time, m_time]]}
end
end
end
end
end
def save_category archive_file_category, in_category
category = {
title: {"zh_tw" => in_category, "en" => in_category},
key: "import_#{category}"
}
archive_file_category.save(category)
end
def save_file_multiples archive_file_multiples, grid ,archive_id,title, file, c_time, m_time
a_file = File.open(file) rescue nil
if a_file
filename = File.basename(file)
archive_file = {
file_title: {"zh_tw" => title, "en" => title },
choose_lang: ["zh_tw", "en"],
file: filename,
archive_file_id: archive_id,
created_at: c_time,
updated_at: m_time
}
a_file_id = archive_file_multiples.save(archive_file)
grid.put(a_file, filename: "assets/archive_file_multiple/file/#{a_file_id}/#{filename}")
end
end
def save_archive archive_files, category_id
archive = {
title: {"zh_tw" => " ", "en" => " "},
archive_file_category_id: category_id,
is_top: false,
is_hot: false,
is_hidden: false,
created_at: c_time,
updated_at: m_time
}
archive_files.save(archive)
end
which_site.each do |site, categories|
db = MongoClient.new("localhost", 27017).db("#{DB_BASE_NAME}_#{site}")
categories.each do |category, data|
archive_file_category = db.collection('archive_file_categories')
category_id = save_category archive_file_category, category
archive_files = db.collection('archive_files')
archive_id = save_archive archive_files, category_id
grid = Grid.new(db)
archive_file_multiples = db.collection('archive_file_multiples')
file_ids = []
data.each do |file|
save_file_multiples(archive_file_multiples, grid ,archive_id , *file)
end
end
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

35
lib/rss_ntu_0_to_11.rb Normal file
View File

@ -0,0 +1,35 @@
# encoding: utf-8
require 'mongo'
include Mongo
DB_BASE_NAME = "production"
main_db = MongoClient.new("localhost", 27017).db("#{DB_BASE_NAME}_#{0}")
main_bulletin = main_db["bulletins"]
main_cat = main_db["bulletin_categories"]
copy_db = MongoClient.new("localhost", 27017).db("#{DB_BASE_NAME}_#{11}")
copy_bulletin = copy_db["bulletins"]
copy_cat = copy_db["bulletin_categories"]
main_cat.find(key: /rss_/).each do |category|
category_id = \
if cat = copy_cat.find_one(key: category['key'])
cat['_id']
else
copy_category = category.clone
copy_category['_id'] = BSON::ObjectId.new
copy_cat.save copy_category
end
main_bulletin.find(bulletin_category_id: category['_id']).each do |bulletin|
unless copy_bulletin.find_one(rss_link: bulletin['rss_link'])
copybulletin = bulletin.clone
copybulletin['_id'] = BSON::ObjectId.new
copybulletin['bulletin_category_id'] = category_id
bulletin_id = copy_bulletin.save copybulletin
end
end
end

129
lib/rss_ntu_job.rb Normal file
View File

@ -0,0 +1,129 @@
# encoding: utf-8
require 'rss'
require 'mongo'
SITES = { "總務處-各單位公告" => "0",
"總務處-文書組" => "1",
"總務處-出納組" => "2",
"總務處-事務組" => "3",
"總務處-保管組" => "5",
"總務處-採購組" => "6",
"總務處-經營管理組" => "7",
"總務處-駐衛警察隊" => "9",
"總務處-營繕組" => "10",
"總務處-總務處" => "11",
"社會科學院-社會科學院總務分處" => "4",
"醫學院-醫學院總務分處" => "8" }
SITE_KEYS = SITES.keys
DB_BASE_NAME = "production"
all = {}
continue = true
i = 1
yesterday = Time.now - 86400
while continue do
open("http://ann.cc.ntu.edu.tw/asp/rss.asp?page=#{i}") do |rss|
feed = RSS::Parser.parse(rss.read.encode('utf-8', 'big5', invalid: :replace, undef: :replace, replace: '').gsub('<pubDate>Wes,', '<pubDate>Wed,').gsub(/(encoding=\"big5\")/, 'encoding="utf-8"'))
feed.items.each do |item|
if item.pubDate > yesterday
if SITE_KEYS.include?(item.author)
author = item.author.strip
category = item.category.to_s.gsub(/\<(\/)*category\>/, '')
if all[author]
all[author][item.link.strip] = {title: item.title.strip, author: author, link: item.link.strip, date: item.pubDate, category: category, description: item.description.gsub("\r\n", '<br/>').strip}
else
all[author] = {item.link.strip => {title: item.title.strip, author: author, link: item.link.strip, date: item.pubDate, category: category, description: item.description.gsub("\r\n", '<br/>').strip}}
end
end
else
continue = false
break
end
end
end
i += 1
end
# Get corresponding category_id or create a new one
def get_category_id(category, categories, coll_cat)
if categories.keys.include? "rss_#{category}"
[categories["rss_#{category}"], categories]
else
cat = {
_type: "BulletinCategory",
key: "rss_#{category}",
disable: false,
title: {:zh_tw => category},
created_at: Time.now,
updated_at: Time.now
}
categories["rss_#{category}"] = result = coll_cat.save(cat)
[result, categories]
end
end
# Get categories and id based on a given site number
def get_mongo_and_categories(site_number="0")
db = Mongo::Connection.new("localhost", 27017).db("#{DB_BASE_NAME}_#{site_number}")
coll_bulletin = db["bulletins"]
coll_cat = db["bulletin_categories"]
categories = coll_cat.find().to_a.inject({}) do |categories, category|
categories[category['key']] = category['_id']
categories
end
[categories, coll_bulletin, coll_cat]
end
# Get main site (總務處) categories
@main_categories, @main_coll_bulletin, @main_coll_cat = get_mongo_and_categories
@copy_categories, @copy_coll_bulletin, @copy_coll_cat = get_mongo_and_categories('11')
all.each do |key, value| # Loop through all the authors
site_number = SITES[key]
categories, coll_bulletin, coll_cat = get_mongo_and_categories(site_number) # Get current's site categories
value.each_value do |bul| # Loop through all the items
category_id, categories = get_category_id(bul[:category], categories, coll_cat)
unless coll_bulletin.find_one(rss_link: bul[:link])
bulletin = { _type: "Bulletin",
postdate: bul[:date],
created_at: bul[:date],
updated_at: bul[:date],
is_checked: true,
is_pending: false,
is_rejected: false,
bulletin_category_id: category_id,
title: {:zh_tw => bul[:title]},
text: {:zh_tw => bul[:description]},
available_for_zh_tw: true,
rss_link: bul[:link],
is_top: false,
is_hot: false,
is_hidden: false }
coll_bulletin.save(bulletin)
unless site_number.eql?("0") || @main_coll_bulletin.find_one(rss_link: bul[:link]) # Copy the item to the main site
category_id, @main_categories = get_category_id(bul[:category], @main_categories, @main_coll_cat)
main_bulletin = bulletin.clone
main_bulletin['_id'] = BSON::ObjectId.new
main_bulletin[:bulletin_category_id] = category_id
@main_coll_bulletin.save(main_bulletin)
category_id, @copy_categories = get_category_id(bul[:category], @copy_categories, @copy_coll_cat)
copy_bulletin = bulletin.clone
copy_bulletin['_id'] = BSON::ObjectId.new
copy_bulletin[:bulletin_category_id] = category_id
@copy_coll_bulletin.save(copy_bulletin)
end
end
end
end

113
lib/rss_ntu_migration.rb Normal file
View File

@ -0,0 +1,113 @@
# encoding: utf-8
require 'rss'
require 'mongo'
SITES = { "總務處-各單位公告" => "0",
"總務處-文書組" => "1",
"總務處-出納組" => "2",
"總務處-事務組" => "3",
"總務處-保管組" => "5",
"總務處-採購組" => "6",
"總務處-經營管理組" => "7",
"總務處-駐衛警察隊" => "9",
"總務處-營繕組" => "10",
"總務處-總務處" => "11",
"社會科學院-社會科學院總務分處" => "4",
"醫學院-醫學院總務分處" => "8" }
SITE_KEYS = SITES.keys
DB_BASE_NAME = "production"
all = {}
continue = true
i = 1
while continue do
open("http://ann.cc.ntu.edu.tw/asp/rss.asp?page=#{i}") do |rss|
feed = RSS::Parser.parse(rss.read.encode('utf-8', 'big5', invalid: :replace, undef: :replace, replace: '').gsub('<pubDate>Wes,', '<pubDate>Wed,').gsub(/(encoding=\"big5\")/, 'encoding="utf-8"'))
feed.items.size
feed.items.each do |item|
if SITE_KEYS.include?(item.author)
author = item.author.strip
category = item.category.to_s.gsub(/\<(\/)*category\>/, '')
if all[author]
all[author][item.link.strip] = {title: item.title.strip, author: author, link: item.link.strip, date: item.pubDate, category: category, description: item.description.gsub("\r\n", '<br/>').strip}
else
all[author] = {item.link.strip => {title: item.title.strip, author: author, link: item.link.strip, date: item.pubDate, category: category, description: item.description.gsub("\r\n", '<br/>').strip}}
end
end
end
continue = false if feed.items.size < 100
end
i += 1
end
# Get corresponding category_id or create a new one
def get_category_id(category, categories, coll_cat)
if categories.keys.include? "rss_#{category}"
[categories["rss_#{category}"], categories]
else
cat = {
_type: "BulletinCategory",
key: "rss_#{category}",
disable: false,
title: {:zh_tw => category},
created_at: Time.now,
updated_at: Time.now
}
categories["rss_#{category}"] = result = coll_cat.save(cat)
[result, categories]
end
end
# Get categories and id based on a given site number
def get_mongo_and_categories(site_number="0")
db = Mongo::Connection.new("localhost", 27017).db("#{DB_BASE_NAME}_#{site_number}")
coll_bulletin = db["bulletins"]
coll_cat = db["bulletin_categories"]
categories = coll_cat.find().to_a.inject({}) do |categories, category|
categories[category['key']] = category['_id']
categories
end
[categories, coll_bulletin, coll_cat]
end
# Get main site (總務處) categories
@main_categories, @main_coll_bulletin, @main_coll_cat = get_mongo_and_categories
all.each do |key, value| # Loop through all the authors
site_number = SITES[key]
categories, coll_bulletin, coll_cat = get_mongo_and_categories(site_number) # Get current's site categories
value.each_value do |bul| # Loop through all the items
category_id, categories = get_category_id(bul[:category], categories, coll_cat)
unless coll_bulletin.find_one(rss_link: bul[:link])
bulletin = { _type: "Bulletin",
postdate: bul[:date],
created_at: bul[:date],
updated_at: bul[:date],
is_checked: true,
is_pending: false,
is_rejected: false,
bulletin_category_id: category_id,
title: {:zh_tw => bul[:title]},
text: {:zh_tw => bul[:description]},
available_for_zh_tw: true,
rss_link: bul[:link],
is_top: false,
is_hot: false,
is_hidden: false }
coll_bulletin.save(bulletin)
unless site_number.eql? "0" # Copy the item to the main site
category_id, @main_categories = get_category_id(bul[:category], @main_categories, @main_coll_cat)
main_bulletin = bulletin.clone
main_bulletin['_id'] = BSON::ObjectId.new
main_bulletin[:bulletin_category_id] = category_id
@main_coll_bulletin.save(main_bulletin)
end
end
end
end

View File

@ -310,6 +310,74 @@ namespace :migrate do
Rake::Task["web_link_url:web_link_url_i18n"].execute
end
task :save_users => :environment do
User.where(:email.not => /guest/).each{|s|s.save}
end
task :fix_bulletin_rss_available_lang => :environment do
Bulletin.all.each do |bull|
if bull.create_user_id.nil?
bull.update_attribute(:available_for_zh_tw, true)
end
end
end
task :fix_imported_data => :environment do
categories = BulletinCategory.where(key: /import_/).entries
unless categories.blank?
categories.each do |category|
bulletins = category.bulletins
unless bulletins.blank?
bulletins.each do |bulletin|
unless bulletin.bulletin_files.blank?
file = bulletin.bulletin_files[0]
bulletin.text_translations = file.description_translations
bulletin.save
file.update_attribute(:description, nil)
end
end
end
end
end
categories = ArchiveFileCategory.where(key: /import_/).entries
unless categories.blank?
categories.each do |category|
files = category.archive_files
unless files.blank?
files.each{|file| file.update_attributes({is_top: false, is_hot: false, is_hidden: false})}
end
end
end
end
task :delete_rss_announcement => :environment do
categories = BulletinCategory.where(key: /rss_/).entries
unless categories.blank?
categories.each do |category|
bulletins = category.bulletins
unless bulletins.blank?
bulletins.each(&:destroy)
end
end
end
end
task :fix_imported_rss => :environment do
categories = BulletinCategory.where(key: /rss_/).entries
unless categories.blank?
categories.each do |category|
bulletins = category.bulletins
unless bulletins.blank?
bulletins.each do |bulletin|
bulletin.update_attribute(:is_top, false) unless bulletin.is_top?
bulletin.update_attribute(:is_hot, false) unless bulletin.is_hot?
bulletin.update_attribute(:is_hidden, false) unless bulletin.is_hidden?
end
end
end
end
end
task :fix_tagged_ids => :environment do
Tag.all.each do |tag|
tag.taggings.each do |tagging|

View File

@ -0,0 +1,183 @@
# encoding: utf-8
namespace :mongo_files do
MODELS = { 'ad_image' => 'file',
'archive_file_multiple' => 'file',
'asset' => 'data',
'bulletin' => 'image',
'bulletin_file' => 'file',
'design' => 'zip_file',
'design_file' => 'file',
'gallery_image' => 'file',
'image' => 'file',
'lab_file' => 'file',
'location_info' => 'file',
'preview_file' => 'file',
'project_file' => 'file',
'research_file' => 'file',
'site' => 'default_image',
'stylesheet' => 'file_orig',
'user' => 'avatar',
'writing_book_file' => 'file',
'writing_conference_file' => 'file',
'writing_journal_file' => 'file',
'writing_patent_file' => 'file' }
IMAGE_UPLOADER_MODELS = %w[ad_image bulletin image site]
# ad_banner
# bulletin
# design
# site
task :clean => :environment do
@files = Mongoid.database['fs.files']
@chunks = Mongoid.database['fs.chunks']
clean_duplicates
clean_unused
remove_objects
# remove_unlinked
end
# Remove unused files from db
def clean_unused
db_array = @files.find().inject([]) do |db_files, file|
db_files << file['filename']
db_files
end
p "# of files in db: #{db_array.size}"
name_array = MODELS.inject([]) do |model_files, (model, type)|
model.classify.constantize.all.each do |item|
url = item.send(type).url
thumb_url = item.send(type).thumb.url rescue nil
if url && !url.eql?('sign-in-logo.png')
url = url.gsub('/gridfs/', '')
model_files << url
end
if thumb_url && !thumb_url.eql?('sign-in-logo.png')
thumb_url = thumb_url.gsub('/gridfs/', '')
model_files << thumb_url
end
end
model_files
end
p "# of files from uploaders: #{name_array.size}"
useless_files = db_array - name_array
p "# of unmatched files: #{useless_files.size}"
useless_files.each do |file|
id = @files.find_one('filename' => file)['_id']
@files.remove('_id' => id)
@chunks.remove('files_id' => id)
end
# p files.remove('filename' => { "$in" => useless_files})
end
# Remove duplicate files from db
def clean_duplicates
p "# of files in db: #{@files.count}"
file_hash = @files.find().inject({}) do |db_files, file|
name = file['filename']
if db_files[name]
db_files[name] += [file['_id']]
else
db_files[name] = [file['_id']]
end
db_files
end
file_array = file_hash.inject([]) do |files, (key, value)|
files += value.drop(1) if value.size > 1
files
end
p "# of duplicate ids to delete: #{file_array.size}"
file_array.each do |id|
@files.remove('_id' => id)
@chunks.remove('files_id' => id)
end
end
task :file_size => :environment do
files = Mongoid.database['fs.files']
size_array = files.find().inject([]) do |size, file|
# size << [file['length'], file['filename']]
size << [file['filename'], file['length']]
size
end
size_array.sort.each do |pair|
p "#{pair[0]} - #{pair[1]}"
end
p size_array.size
end
def remove_objects
# Destroy writing_journals and writing_journal_files
Mongoid.database['writing_journals'].remove()
Mongoid.database['writing_journal_files'].remove()
# Destroy bulletins, bulletin_files and bulletin_links
Bulletin.excludes(create_user_id: nil).destroy
BulletinFile.destroy_all
BulletinLink.destroy_all
# Destroy gallery_albums and gallery_images
Mongoid.database['gallery_albums'].remove()
Mongoid.database['gallery_images'].remove()
db_array = @files.find().inject([]) do |db_files, file|
db_files << file['filename'] if file['filename'] =~ /writing_journal_file|news_bulletin_file|bulletin_file|gallery_image|image\/image/
db_files
end
p db_array.size
db_array.each do |file|
id = @files.find_one('filename' => file)['_id']
@files.remove('_id' => id)
@chunks.remove('files_id' => id)
end
end
def remove_unlinked
# name_array = AdBanner.all.inject([]) do |files, banner|
# banner.ad_images.inject(files) do |image_files, image|
# url = image.file.url
# thumb_url = image.file.thumb.url rescue nil
# if url && !url.eql?('sign-in-logo.png')
# url = url.gsub('/gridfs/', '')
# image_files << url
# end
# if thumb_url && !thumb_url.eql?('sign-in-logo.png')
# thumb_url = thumb_url.gsub('/gridfs/', '')
# image_files << thumb_url
# end
# image_files
# end
# files
# end
name_array = Design.all.inject([]) do |files, design|
files += design.images.inject(files) do |image_files, image|
p image_files += get_url_and_thumb(image.file)
image_files
end
files
end
p name_array.size
end
def get_url_and_thumb(file)
url = file.url
thumb_url = file.thumb.url rescue nil
files = [url, thumb_url].inject([]) do |urls, current|
urls << current.gsub('/gridfs/', '') if current && !current.eql?('sign-in-logo.png')
urls
end
files
end
task :delete_rss_ann => :environment do
Bulletin.where(create_user_id: nil).destroy
end
end

View File

@ -9,17 +9,17 @@ namespace :web_link_url do
@weblinks.each do |wl|
if wl.url.nil?
if wl.url_translations.is_a?(String)
@wlurl = wl.url_translations
wl.url_translations = {}
wl.url_translations["zh_tw"] = @wlurl
wl.url_translations["en"] = @wlurl
@wlurl = wl.url_translations
wl.url_translations = {}
wl.url_translations["zh_tw"] = @wlurl
wl.url_translations["en"] = @wlurl
wl.save
wl.save
else
puts 'no data'

View File

@ -0,0 +1,9 @@
// This list may be created by a server logic page PHP/ASP/ASPX/JSP in some backend system.
// There templates will be displayed as a dropdown in all media dialog if the "template_external_list_url"
// option is defined in TinyMCE init.
var tinyMCETemplateList = [
// Name, URL, Description
["Simple snippet", "/tinymce/templates/snippet1.htm", "Simple HTML snippet."],
["Layout", "/tinymce/templates/layout1.htm", "HTML Layout."]
];

View File

@ -0,0 +1,15 @@
<table border="1">
<thead>
<tr>
<td>Column 1</td>
<td>Column 2</td>
</tr>
</thead>
<tbody>
<tr>
<td>Username: {$username}</td>
<td>Staffid: {$staffid}</td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1 @@
This is just some <strong>code</strong>.

View File

@ -95,6 +95,7 @@ class Panel::Announcement::BackEnd::BulletinsController < OrbitBackendController
# GET /bulletins/1/edit
def edit
@bulletin = Bulletin.find(params[:id])
@users = @bulletin.get_users
if !current_user.admin? && (@bulletin.is_rejected? || @bulletin.is_checked?)
redirect_to :action => :index
else

View File

@ -28,6 +28,7 @@ class Bulletin
field :create_user_id
field :update_user_id, :class_name => "User"
field :user_ids
field :is_top, :type => Boolean, :default => false
field :is_hot, :type => Boolean, :default => false
@ -40,6 +41,7 @@ class Bulletin
field :not_checked_reason
field :public, :type => Boolean, :default => true
field :rss_link
scope :can_display, where(is_checked: true, is_rejected: false, is_pending: false)
scope :available_for_lang, ->(locale){ where("available_for_#{locale}".to_sym => true) }
@ -215,6 +217,10 @@ class Bulletin
preview_object
end
def get_users
User.find(self.user_ids) rescue []
end
protected

View File

@ -116,6 +116,17 @@
<% elsif current_user.admin? %>
<%= f.hidden_field :is_checked,:value => true%>
<% end %>
<div id="widget-member" class="widget-box widget-size-300">
<div class="widget-action clear tip" title="Rejected Report">
<a class="action"><i class="icon-cog icon-white"></i></a>
</div>
<h3 class="widget-title"><i class="icons-tag"></i><%= t(:promoter) %></h3>
<div class="widget-content clear form-horizontal">
<%= render partial: 'admin/member_selects/selection_box', locals: {field: 'bulletin[user_ids][]', users: @users} %>
</div>
</div>
</div>
@ -130,7 +141,7 @@
<%= f.label :category,t(:category)%>
<%= f.select :bulletin_category_id, @bulletin_categorys.collect{|t| [ t.title, t.id ]}, {}, :class => "input-medium" %>
<ul class="nav nav-tabs">
<%# @site_valid_locales.each_with_index do |locale, i| %>
<% @site_valid_locales.each_with_index do |locale, i| %>

View File

@ -15,6 +15,7 @@
<div class="news_paragraph">
<%= @bulletin.text.html_safe rescue '' %>
</div>
<div class="linkAndFile">
<% if @bulletin.bulletin_links.size > 0 %>
<div>
@ -36,6 +37,22 @@
</div>
</div>
<% end %>
<% unless @bulletin.rss_link.blank? %>
<div>
<%= link_to t('ntu.rss_origin'), @bulletin.rss_link %>
</div>
<% end %>
</div>
<% unless @bulletin.user_ids.blank? %>
<div class="promoter">
<div>
<p><%= t(:promoter) %></p>
<span><%= @bulletin.get_users.map{|u| "<span>#{u.name}</span>"}.join(', ').html_safe %></span>
</div>
</div>
<% end %>
<%= share_links(@bulletin, 'announcement') %>
<%= render partial: 'admin/member_selects/promoter_front', locals: {users: @bulletin.get_users} %>

View File

@ -133,4 +133,28 @@ border-radius: 3px;
}
.o-archives.layout-table .o-archives-category {
font-weight: normal;
}
.o-archives.layout-table table {
width: 100%;
}
.o-archives.layout-table tbody tr td {
border-top: none;
padding: 0;
}
.o-archives.layout-table tbody tr:nth-child(odd) td {
border-bottom: none;
padding: 10px 0 0;
}
.o-archives.layout-table tbody tr:nth-child(even) td .o-archives-category {
margin-bottom: 5px;
}
.o-archives.layout-table tbody .o-archives-list-item ol {
margin: 0;
padding: 0;
}
.o-archives.layout-table tbody .promoter-block {
margin: 0 0 10px;
padding: 0;
background-color: transparent;
border: none;
}

View File

@ -70,6 +70,7 @@ class Panel::Archive::BackEnd::ArchiveFilesController < OrbitBackendController
# GET /archive_files/1/edit
def edit
@archive_file = ArchiveFile.find(params[:id])
@users = @archive_file.get_users
@tags = get_tags
end

View File

@ -60,6 +60,12 @@ class Panel::Archive::FrontEnd::ArchiveFilesController < OrbitWidgetController
get_categorys
end
def download
file = ArchiveFileMultiple.find(params[:id])
file.update_attribute(:download_count, file.download_count + 1)
render text: 'OK'
end
protected
def reload_archive_files

View File

@ -20,11 +20,12 @@ class ArchiveFile
field :create_user_id
field :update_user_id
field :is_top, :type => Boolean, :default => false
field :is_hot, :type => Boolean, :default => false
field :is_hidden, :type => Boolean, :default => false
field :user_ids
field :is_top, :type => Boolean, :default => false
field :is_hot, :type => Boolean, :default => false
field :is_hidden, :type => Boolean, :default => false
scope :can_display,where(is_hidden: false)
# belongs_to :archive_file_category
@ -85,4 +86,8 @@ class ArchiveFile
end
end
def get_users
User.find(self.user_ids) rescue []
end
end

View File

@ -9,7 +9,7 @@ class ArchiveFileMultiple
field :file_title, localize: true
# field :description
field :choose_lang, :type => Array, :default => nil
field :download_count, type: Integer, default: 0
field :should_destroy, :type => Boolean
default_scope asc(:sort_number)

View File

@ -31,8 +31,18 @@
<%= tag.name %>
<% end %>
</div>
</div>
</div>
<div id="widget-member" class="widget-box widget-size-300">
<div class="widget-action clear tip" title="Rejected Report">
<a class="action"><i class="icon-cog icon-white"></i></a>
</div>
<h3 class="widget-title"><i class="icons-tag"></i><%= t(:promoter) %></h3>
<div class="widget-content clear form-horizontal">
<%= render partial: 'admin/member_selects/selection_box', locals: {field: 'archive_file[user_ids][]', users: @users} %>
</div>
</div>
</div>
@ -86,12 +96,13 @@
<th>File</th>
<th>File Name</th>
<th class="span2"><%= t('呈現語系')%></th>
<th class="span2"><%= t('archive.download_count')%></th>
<th class="span1"></th>
</tr>
</thead>
<tfoot>
<tr>
<td style="text-align:center" colspan="4">
<td style="text-align:center" colspan="6">
<div id='add_archive_file_multiple' class="info_input archive_file_multiples_block">
<%= hidden_field_tag 'archive_file_multiple_field_count', @archive_file.archive_file_multiples.count %>
<a class="add"><span class="btn btn-primary btn-small"><i class="icon-plus icon-white"></i> ADD/新增</span></a>

View File

@ -4,7 +4,7 @@
<td>
<div class="control-group">
<div class="controls">
<%= f.text_field :sort_number %>
<%= f.text_field :sort_number, class: 'input-mini' %>
</div>
</div>
</td>
@ -47,18 +47,19 @@
<% end %>
<%= hidden_field_tag 'archive_file[archive_file_multiples_attributes][0][choose_lang][]', '' %>
</td>
<td>
<span class="action">
<% if form_file.new_record? %>
<a class="delete"><i class="icon-remove"></i></a>
<% else %>
<%= f.hidden_field :id %>
<a class="remove_existing_record"><i class="icon-remove"></i></a>
<%= f.hidden_field :should_destroy, :value => nil, :class => 'should_destroy' %>
<% end %>
</span>
<%= form_file.download_count %>
</td>
<td>
<span class="action">
<% if form_file.new_record? %>
<a class="delete"><i class="icon-remove"></i></a>
<% else %>
<%= f.hidden_field :id %>
<a class="remove_existing_record"><i class="icon-remove"></i></a>
<%= f.hidden_field :should_destroy, :value => nil, :class => 'should_destroy' %>
<% end %>
</span>
</td>
</tr>

View File

@ -8,7 +8,7 @@
<tr>
<th class="column-ctrl col-title"><%= sortable(:title, t("archive.Title"))%></th>
<th class="column-ctrl col-file"><%= t("archive.Files")%></th>
<th class="column-ctrl col-category"><%= sortable(:archive_file_category, t("archive.Category"))%></th>
<th class="column-ctrl col-file"><%= t(:promoter)%></th>
</tr>
</thead>
<tbody>
@ -23,7 +23,7 @@
<% post.archive_file_multiples.asc(:_id).each do | afile | %>
<% if afile.file.file and afile.choose_lang_display(I18n.locale.to_s) %>
<li>
<%= link_to afile.file_title, afile.file.url, {:target => '_blank', :title => afile.file_title, :class => "o-archives-file"} %>
<%= link_to afile.file_title, afile.file.url, {:target => '_blank', :title => afile.file_title, :class => "o-archives-file download_count", rel: download_panel_archive_front_end_archive_file_path(afile, inner: true)} %>
<%= post.get_file_icon(afile.file.url) %>
</li>
<% end %>
@ -32,9 +32,21 @@
<% end %>
</div>
</td>
<td><div class="o-archives-category">
<%= post.archive_file_category.title %>
</div></td>
<td>
<% unless post.get_users.blank? %>
<div class="promoter-block">
<ul>
<% post.get_users.each do |user| %>
<li class="promoter">
<p>
<%= link_to user.name, "mailto:#{user.email}", class: "promoter-name" %> / <span class="promoter-phone"><%= user.office_tel %></span>
</p>
</li>
<% end %>
</ul>
</div>
<% end %>
</td>
</tr>
<% end %>
@ -44,13 +56,10 @@
<%= paginate @archive_files, :param_name => :page_main, :params => {:inner => 'false'} %>
<%= stylesheet_link_tag "archive/archives" %>
<script>
$(document).ready(function(){
$('.download_count').on('click', function(){
$.getScript($(this).attr('rel'));
});
});
</script>

View File

@ -7,12 +7,3 @@
</div>
<%= stylesheet_link_tag "archive/archives" %>

View File

@ -27,4 +27,6 @@
</div>
</div>
<%= render partial: 'admin/member_selects/promoter_front', locals: {users: @archive_file.get_users} %>
<%= stylesheet_link_tag "archive/archives" %>

View File

@ -2,6 +2,7 @@ en:
archive:
archive: Archive
download_count: Download count
Title: Title
Files: Files
Category: Category

View File

@ -2,6 +2,7 @@ zh_tw:
archive:
archive: 檔案室
download_count: 下載次數
Title: 標題
Files: 檔案
Category: 類別

View File

@ -12,7 +12,11 @@ Rails.application.routes.draw do
end
namespace :front_end do
match "archive_files" => "archive_files#index"
resources :archive_files
resources :archive_files do
member do
get 'download'
end
end
end
namespace :widget do
match "index" => "archive_files#index"

View File

@ -2,6 +2,8 @@ class Panel::Ask::BackEnd::AskAcknowledgementsController < OrbitBackendControlle
include AdminHelper
include OrbitControllerLib::DivisionForDisable
before_filter :for_app_manager
def initialize
super
@app_title = 'ask_acknowledgement'

View File

@ -3,6 +3,8 @@ class Panel::Ask::BackEnd::AskAdminsController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
before_filter :for_app_manager
def initialize
super
@app_title = 'ask_admins'

View File

@ -3,6 +3,8 @@ class Panel::Ask::BackEnd::AskCategoriesController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
before_filter :for_app_manager
def initialize
super
@app_title = 'ask_categories'

View File

@ -5,9 +5,11 @@ class Panel::Ask::BackEnd::AskQuestionsController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
before_filter :for_app_manager
def initialize
super
@app_title = 'ask_questions'
@app_title = 'ask'
end
def index

View File

@ -1,8 +1,10 @@
# encoding: utf-8
class Panel::Ask::BackEnd::AskRepliesController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
before_filter :for_app_manager
def initialize
super
@app_title = 'ask_replies'
@ -19,11 +21,67 @@ class Panel::Ask::BackEnd::AskRepliesController < OrbitBackendController
end
def update
@ask_question = AskQuestion.find(params[:ask_question_id])
@ask_reply = AskReply.find(params[:id])
@ask_reply.update_attributes(params[:ask_reply])
if @ask_reply.send_email?
Resque.enqueue(SendAskReplyMail, @ask_reply.ask_question.id)
end
params[:school][:depts].each do |dns|
send_request(dns, @ask_question, @ask_reply)
end unless params[:school].nil?
redirect_to panel_ask_back_end_ask_questions_path, notice: t('ask.reply_success')
end
def send_request(dep_dns, current_question, current_reply)
require 'net/http'
require 'uri'
require 'json'
uri_path = "/panel/ask/back_end/ask_requests/auth_request"
uri = URI.parse("http://" + dep_dns + uri_path)
body = {
'auth_token' => '3kjlfksjDFJ'
}
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(body)
response = http.request(request)
puts "Response #{response.code} #{response.message}: #{response.body}"
if response.code == "200"
uri_path = "/panel/ask/back_end/ask_requests/transfer_request"
uri = URI.parse("http://" + dep_dns + uri_path)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
body = {
'name' => current_question.name,
'title' => current_question.title,
'identity' => current_question.identity,
'email' => current_question.email,
'phone' => current_question.phone,
'tax' => current_question.tax,
'content' => current_question.content,
}
request.set_form_data(body)
response = http.request(request)
if response.code != "200"
new_status = "轉介其他單位" + "(" + response.code + ")"
current_reply.update_attributes(status: new_status)
else
new_status = "轉介其他單位" + "(" + "success!" + ")"
current_reply.update_attributes(status: new_status)
end
end
puts "Response #{response.code} #{response.message}: #{response.body}"
# flash[:notice] = response.body
# flash[:notice] = "Response #{response.code} #{response.message}: #{response.body}"
end
end

View File

@ -0,0 +1,35 @@
# encoding: utf-8
class Panel::Ask::BackEnd::AskRequestsController < OrbitBackendController
include AdminHelper
include OrbitControllerLib::DivisionForDisable
def auth_request
render :json => "#{params}"
end
def transfer_request
if !AskCategory.where(key: "transfered_question").any?
@ask_category = AskCategory.new(name: "transfered_question", key: "transfered_question")
@ask_category.save!
end
category = AskCategory.where(key: "transfered_question")
@transfered_question = AskQuestion.new(
name: params['name'],
identity: params['identity'],
email: params['email'],
phone: params['phone'],
tax: params['tax'],
title: params['title'],
content: params['content'],
ask_category_id: category.first.id)
@transfered_question.ask_reply = AskReply.new
@transfered_question.ask_reply.update_attributes(status: "待處理(轉)")
@transfered_question.save
render :json => "#{params}"
end
end

View File

@ -2,7 +2,8 @@ class AskCategory
include Mongoid::Document
include Mongoid::Timestamps
include OrbitCoreLib::ObjectDisable
include OrbitCoreLib::ObjectAuthable
field :name, localize: true
field :key

View File

@ -1,3 +1,37 @@
<script type="text/javascript">
$(document).ready(function() {
if ($("#ask_reply_status").val() == '轉介其他單位') { $('.dept_options').show(); }
$("#ask_reply_status").change(function() {
var local_host = "<%= request.host %>:<%= request.port %>";
$('input[type=checkbox]').each(function() {
if ($(this).val() == local_host) {
$(this).addClass("hide");
$(this).next().addClass("hide");
}
});
$('.dept_options').slideUp();
if ($(this).find('option:selected').attr('value') == '轉介其他單位') {
$('.dept_options').slideDown();
}
});
});
</script>
<style type="text/css">
.dept_options {
display: none;
}
.hide {
display: none;
}
</style>
<div id="ask_question_reply">
<%= form_for @ask_reply, url: @url, method: @method do |f| %>
<table class="table">
@ -31,7 +65,25 @@
['已處理', '已處理'],
['轉介其他單位', '轉介其他單位']
] %></td>
<td id="XXX"></td>
</tr>
<tr>
<td colspan="5" class="dept_options">
<div class="dept_options">
<%= check_box("school", "depts", {:multiple => true}, "localhost:3000", nil) %><%= label_tag("localhost:3000", "總務長室暨總務處秘書室") %>
<%= check_box("school", "depts", {:multiple => true}, "localhost:4000", nil) %><%= label_tag("localhost:4000", "文書組") %>
<%= check_box("school", "depts", {:multiple => true}, "事務組", nil) %><%= label_tag(:dep3, "事務組") %>
<%= check_box("school", "depts", {:multiple => true}, "保管組", nil) %><%= label_tag(:dep4, "保管組") %>
<%= check_box("school", "depts", {:multiple => true}, "營繕組", nil) %><%= label_tag(:dep5, "營繕組") %>
<%= check_box("school", "depts", {:multiple => true}, "出納組", nil) %><%= label_tag(:dep6, "出納組") %>
<%= check_box("school", "depts", {:multiple => true}, "採購組", nil) %><%= label_tag(:dep7, "採購組") %>
<%= check_box("school", "depts", {:multiple => true}, "經營管理組", nil) %><%= label_tag(:dep8, "經營管理組") %>
<%= check_box("school", "depts", {:multiple => true}, "駐警隊", nil) %><%= label_tag(:dep9, "駐警隊") %>
<%= check_box("school", "depts", {:multiple => true}, "社科院總務分處", nil) %><%= label_tag(:dep10, "社科院總務分處") %>
<%= check_box("school", "depts", {:multiple => true}, "醫學院總務分處", nil) %><%= label_tag(:dep11, "醫學院總務分處") %>
</div>
</td>
</tr>
<tr>
<td colspan="5">
<%= f.label :send_email %><%= f.radio_button :send_email, 1, checked: @ask_reply.send_email? %><%= t('ask.yes') %>

View File

@ -35,7 +35,7 @@ $(document).ready(function(){
<div class="control-group">
<%= f.label :ask_category_id, class: 'control-label required' %>
<div class="controls">
<%= f.collection_select :ask_category_id, AskCategory.all, :id, :name %>
<%= f.collection_select :ask_category_id, AskCategory.all.select { |c| c.key != 'transfered_question' }, :id, :name %>
</div>
</div>
<div class="control-group">

View File

@ -11,10 +11,13 @@ Rails.application.routes.draw do
end
resources :ask_replies
end
resources :ask_categories
resources :ask_acknowledgements
resources :ask_admins
match "ask_requests/auth_request" => "ask_requests#auth_request", :as => 'auth_request'
match "ask_requests/transfer_request" => "ask_requests#transfer_request", :as => 'transfer_request'
end
namespace :front_end do

View File

@ -23,26 +23,26 @@ module Ask
side_bar do
head_label_i18n 'ask.ask', icon_class: 'icons-light-bulb'
available_for [:admin,:manager,:sub_manager]
available_for [:admin]
active_for_controllers({ private: ['ask_questions'] })
head_link_path "panel_ask_back_end_ask_questions_path"
context_link 'categories', link_path: 'panel_ask_back_end_ask_categories_path',
priority: 1,
active_for_action: {:ask_categories=>:index},
available_for: [:all]
available_for: [:manager]
context_link 'ask.acknowledgement', link_path: 'panel_ask_back_end_ask_acknowledgements_path',
priority: 1,
available_for: [:all]
available_for: [:manager]
context_link 'ask.admin', link_path: 'panel_ask_back_end_ask_admins_path',
priority: 1,
available_for: [:all]
available_for: [:manager]
context_link 'ask.export', link_path: 'export_panel_ask_back_end_ask_questions_path',
priority: 1,
available_for: [:all]
available_for: [:manager]
end
end

Some files were not shown because too many files have changed in this diff Show More