Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun

* 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder:
  统计在线用户
  后台添加在线pods数统计
  增加当前pod数
  实训、实践课程发送至课堂的跳转更改
  学生签到
  调整
  签到
  签到
  签到
ecloud_sso
harry 5 years ago
commit 9ecff11e57

@ -5,6 +5,14 @@ class Admins::DashboardsController < Admins::BaseController
@month_active_user_count = User.where(last_login_on: current_month).count
@new_user_count = User.where(created_on: current_month).count
shixun_tomcat = edu_setting('cloud_bridge')
uri = "#{shixun_tomcat}/bridge/monitor/getPodsInfo"
res = interface_post uri, params, 502, "数据接口延迟"
if res['code'] == 0
@pod_num = res['sum'] || 0
end
end
def month_active_user

@ -321,7 +321,7 @@ class ApplicationController < ActionController::Base
end
if !User.current.logged? && Rails.env.development?
User.current = User.find 1
User.current = User.find 3117
end

@ -35,6 +35,7 @@ module LoginHelper
UserAction.create(action_id: user&.id, action_type: 'Login', user_id: user&.id, ip: request.remote_ip)
user.update_column(:last_login_on, Time.now)
# 注册完成后有一天的试用申请(先去掉)
# UserDayCertification.create(user_id: user.id, status: 1)
end
@ -44,6 +45,8 @@ module LoginHelper
if autologin = cookies.delete(autologin_cookie_name)
User.current.delete_autologin_token(autologin)
end
UserOnline.logout(User.current.id)
User.current.delete_session_token(session[:tk])
self.logged_user = nil
end
@ -52,6 +55,7 @@ module LoginHelper
default_yun_session = "#{laboratory.try(:identifier).split('.').first}_user_id"
# end
session[:"#{default_yun_session}"] = nil
session[:request_user_id] = nil
end
# Sets the logged in user
@ -78,6 +82,8 @@ module LoginHelper
# # end
# session[:user_id] = user.id
UserOnline.login(user.id)
session[:request_user_id] = user.id
session[:"#{default_yun_session}"] = user.id
session[:ctime] = Time.now.utc.to_i
session[:atime] = Time.now.utc.to_i

@ -4,6 +4,7 @@ class MainController < ApplicationController
skip_before_action :setup_laboratory
def first_stamp
UserOnline.login(session[:request_user_id]) if session[:request_user_id]
render :json => { status: 0, message: Time.now.to_i }
end

@ -0,0 +1,84 @@
class Weapps::AttendancesController < ApplicationController
before_action :require_login
before_action :find_course, only: [:create, :index, :student_attendances]
before_action :find_attendance, except: [:create, :index, :student_attendances]
before_action :user_course_identity
before_action :teacher_allowed, only: [:create]
def create
ActiveRecord::Base.transaction do
attendance = @course.course_attendances.create!(create_params.merge(user_id: current_user.id))
unless params[:group_ids].blank?
group_ids = @course.charge_group_ids(current_user) & params[:group_ids]
group_ids.each do |group_id|
@course.course_attendance_groups.create!(course_group_id: group_id, course_attendance: attendance)
end
else
@course.course_attendance_groups.create!(course_group_id: 0, course_attendance: attendance)
end
render_ok({attendance_id: attendance.id})
end
end
def index
end
def student_attendances
tip_exception(403, "") if @user_course_identity != Course::STUDENT
member = @course.students.find_by(user_id: current_user.id)
current_date = Date.current
current_end_time = Time.current.strftime("%H:%M:%S")
# 先算出该学生所在分班的签到id
# 分班id为0 表示签到不限制分班
group_ids = [member&.course_group_id.to_i, 0]
all_attendance_ids = @course.course_attendance_groups.where(course_group_id: group_ids).pluck(:course_attendance_id)
@history_attendances = @course.course_attendances.where(id: all_attendance_ids.uniq).
where("attendance_date < '#{current_date}' or (attendance_date = '#{current_date}' and end_time < '#{current_end_time}')").order("id desc")
@current_attendance = @course.course_attendances.where(id: all_attendance_ids.uniq).
where("attendance_date = '#{current_date}' and start_time <= '#{current_end_time}' and end_time > '#{current_end_time}'").take
@history_count = @history_attendances.size
student_attendance_ids = @history_attendances.pluck(:id)
student_attendance_ids += @current_attendance.present? ? [@current_attendance.id] : []
if student_attendance_ids.uniq.blank?
@normal_count = 0
@leave_count = 0
@absence_count = 0
else
@normal_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: 1).size
@leave_count = @course.course_member_attendances.where(course_attendance_id: student_attendance_ids, attendance_status: 2).size
@absence_count = student_attendance_ids.uniq.size - @normal_count - @leave_count
end
@all_history_count = @history_attendances.size
@history_attendances = paginate @history_attendances.includes(:course_member_attendances)
end
def show
end
def update
tip_exception(403, "") unless @user_course_identity < Course::PROFESSOR || @attendance.user_id == current_user.id
@attendance.update!(name: params[:name])
render_ok
end
def destroy
end
private
def create_params
params.permit(:name, :mode, :attendance_date, :start_time, :end_time)
end
def find_attendance
@attendance = CourseAttendance.find params[:id]
@course = @attendance.course
end
end

@ -0,0 +1,31 @@
class Weapps::CourseMemberAttendancesController < ApplicationController
before_action :require_login
def create
tip_exception("签到码不能为空") if params[:code].blank?
tip_exception("attendance_mode参数不对") if [1, 2].include?(params[:attendance_mode])
attendance = CourseAttendance.find_by(attendance_code: params[:code])
tip_exception("签到码输入有误") if attendance.blank? || attendance.course.blank?
member = attendance.course.students.find_by(user_id: current_user.id)
tip_exception("签到码输入有误") if member.blank?
start_time = "#{attendance.attendance_date} #{attendance.start_time}".to_time
end_time = "#{attendance.attendance_date} #{attendance.end_time}".to_time
Rails.logger.info("##############{start_time} #{end_time}")
tip_exception("不在签到时间内") unless start_time < Time.current && Time.current < end_time
current_attendance = attendance.course_member_attendances.find_by(user_id: current_user.id)
tip_exception("请勿重复签到") if current_attendance.present? && current_attendance.attendance_status == 1
tip_exception("您当前是请假状态,无法签到") if current_attendance.present? && current_attendance.attendance_status == 2
tip_exception("您当前是旷课状态,无法签到") if current_attendance.present? && current_attendance.attendance_status == 0
unless current_attendance.present?
attendance.course_member_attendances.create!(course_member_id: member.id, user_id: current_user.id, course_id: attendance.course_id,
course_group_id: member.course_group_id, attendance_status: 1, attendance_mode: params[:attendance_mode] || 2)
end
render_ok
end
end

@ -0,0 +1,7 @@
module Weapps::AttendancesHelper
def student_attendance_status attendance, user
st_attendance = attendance.course_member_attendances.find_by(user_id: user.id)
st_attendance.present? ? st_attendance.attendance_status : 0
end
end

@ -0,0 +1,41 @@
module UserOnline
class << self
def login(user_id)
set_bit(user_id, 1)
end
def logout(user_id)
set_bit(user_id, 0)
end
def set_bit(user_id, flag)
if !Rails.cache.data.exists(cache_key)
Rails.cache.data.setbit(cache_key, user_id, flag)
Rails.cache.data.expire(cache_key, 20 * 60 + 10)
else
Rails.cache.data.setbit(cache_key, user_id, flag)
end
end
def count
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
Rails.cache.data.bitcount(cache_key)
else
0
end
end
def cache_key
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
# 10分钟为一段记录用户在线, 统计范围为20分钟内的线用户
# TODO 更精确时长
begin_hour = Time.now.beginning_of_hour
minutes_piece = (Time.now - begin_hour) / 600
time = begin_hour.since((minutes_piece.to_i - 1) * 600).strftime("%H-%M")
"online_user_#{time}"
else
raise '请配置config.cache_store = redis_store'
end
end
end
end

@ -90,6 +90,11 @@ class Course < ApplicationRecord
# 直播
has_many :live_links, dependent: :destroy
# 签到
has_many :course_attendances, dependent: :destroy
has_many :course_attendance_groups
has_many :course_member_attendances
validate :validate_sensitive_string
scope :hidden, ->(is_hidden = true) { where(is_hidden: is_hidden) }

@ -0,0 +1,33 @@
class CourseAttendance < ApplicationRecord
# mode: 0 两种签到1 二维码签到2 数字签到
belongs_to :course
belongs_to :user
has_many :course_attendance_groups, dependent: :destroy
has_many :course_member_attendances, dependent: :destroy
validates :name, presence: true
validates :mode, presence: true
validates :attendance_date, presence: true
validates :start_time, presence: true
validates :end_time, presence: true
after_create :generate_attendance_code
# 延迟生成邀请码
def attendance_code
return generate_attendance_code
end
# 生成邀请码
CODES = %W(2 3 4 5 6 7 8 9 A B C D E F G H J K L N M O P Q R S T U V W X Y Z)
def generate_attendance_code
code = read_attribute(:attendance_code)
if !code || code.size < 4
code = CODES.sample(4).join
return generate_attendance_code if CourseAttendance.where(attendance_code: code).present?
update_attribute(:attendance_code, code)
end
code
end
end

@ -0,0 +1,5 @@
class CourseAttendanceGroup < ApplicationRecord
belongs_to :course
belongs_to :course_attendance
belongs_to :course_group, optional: true
end

@ -8,6 +8,7 @@ class CourseMember < ApplicationRecord
belongs_to :course_group, counter_cache: true, optional: true
belongs_to :graduation_group, optional: true
has_many :teacher_course_groups, dependent: :destroy
has_many :course_member_attendances, dependent: :destroy
scope :teachers_and_admin, -> { where(role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) }
scope :students, ->(course) { where(course_id: course.id, role: %i[STUDENT])}

@ -0,0 +1,9 @@
class CourseMemberAttendance < ApplicationRecord
# attendance_mode 1 二维码签到2 数字签到3 老师签到
# attendance_status 1 正常签到2 请假0 旷课
belongs_to :course_member
belongs_to :user
belongs_to :course
belongs_to :course_attendance
belongs_to :course_group
end

@ -42,10 +42,7 @@
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last week</span>-->
<!-- </p>-->
</div>
</div>
</div>
@ -63,13 +60,50 @@
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>-->
<!-- <span class="text-nowrap">Since yesterday</span>-->
<!-- </p>-->
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">当前在线用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= UserOnline.count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">当前Pod总数</h5>
<span class="h2 font-weight-bold mb-0"><%= @pod_num.to_i %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
@ -100,14 +134,6 @@
<div class="row mt-5">
<div class="col-xl-8 mb-5 mb-xl-0">
<div class="card shadow">
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <h5 class="mb-0">近7天评测次数</h5>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <div id="evaluate-pie" class="pie"></div>-->
<!-- </div>-->
</div>
</div>
@ -127,92 +153,3 @@
</div>
<!--<div class="container-fluid mt--7">-->
<!-- <div class="row mt-5">-->
<!-- <div class="col-xl-8 mb-5 mb-xl-0">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Page visits</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">/test/</th>-->
<!-- <td>4,569</td>-->
<!-- <td>340</td>-->
<!-- <td>-->
<!-- <i class="fas fa-arrow-up text-success mr-3"></i> 46,53%-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-xl-4">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Test</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col"></th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">-->
<!-- Test-->
<!-- </th>-->
<!-- <td>-->
<!-- 1,480-->
<!-- </td>-->
<!-- <td>-->
<!-- <div class="d-flex align-items-center">-->
<!-- <span class="mr-2">60%</span>-->
<!-- <div>-->
<!-- <div class="progress">-->
<!-- <div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->

@ -1,4 +1,4 @@
json.status 1
json.message "发送成功"
json.course_id @course.id
json.first_category_url module_url(@course.none_hidden_course_modules.first, @course)
json.first_category_url module_url(@course.shixun_course_modules.first, @course)

@ -1,3 +1,3 @@
json.status 1
json.message "发送成功"
json.url module_url(@course.none_hidden_course_modules.first, @course)
json.url module_url(@course.shixun_course_modules.first, @course)

@ -0,0 +1,5 @@
json.(attendance, :name, :mode)
json.attendance_date attendance.attendance_date.strftime("%Y/%m/%d")
json.start_time attendance.start_time.strftime("%H:%M")
json.end_time attendance.end_time.strftime("%H:%M")
json.attendance_status student_attendance_status(attendance, User.current)

@ -0,0 +1,12 @@
json.current_attendance do
json.partial! 'student_attendance', locals: {attendance: @current_attendance} if @current_attendance.present?
end
json.history_attendances @history_attendances do |attendance|
json.partial! 'student_attendance', locals: {attendance: attendance}
end
json.all_history_count @all_history_count
json.normal_count @normal_count
json.leave_count @leave_count
json.absence_count @absence_count

@ -177,6 +177,12 @@ zh-CN:
platform: '直播平台'
live_time: '开播时间'
duration: '直播时长'
course_attendance:
name: '签到名称'
mode: '签到方式'
attendance_date: '签到日期'
start_time: '开始时间'
end_time: '结束时间'

@ -1057,8 +1057,16 @@ Rails.application.routes.draw do
collection do
get :check_invite_code
end
resources :attendances, only: [:index, :update, :create, :show, :destroy], shallow: true do
collection do
get :student_attendances
end
end
end
resources :course_member_attendances, only: [:create]
resources :homework_commons do
post :update_settings, on: :member
end

@ -0,0 +1,16 @@
class CreateCourseAttendances < ActiveRecord::Migration[5.2]
def change
create_table :course_attendances do |t|
t.references :course, index: true
t.references :user, index: true
t.string :name
t.integer :mode, limit: 1, default: 0
t.date :attendance_date
t.time :start_time
t.time :end_time
t.string :attendance_code
t.timestamps
end
end
end

@ -0,0 +1,14 @@
class CreateCourseAttendanceGroups < ActiveRecord::Migration[5.2]
def change
create_table :course_attendance_groups do |t|
t.references :course, index: true
t.references :course_attendance
t.references :course_group, index: true
t.timestamps
end
add_index :course_attendance_groups, [:course_attendance_id, :course_group_id, :course_id], name: "course_group_attendance", unique: true
end
end

@ -0,0 +1,17 @@
class CreateCourseMemberAttendances < ActiveRecord::Migration[5.2]
def change
create_table :course_member_attendances do |t|
t.references :course_member, index: true
t.references :user
t.references :course, index: true
t.references :course_attendance
t.references :course_group, index: true
t.integer :attendance_mode, default: 0
t.integer :attendance_status, default: 0
t.timestamps
end
add_index :course_member_attendances, [:course_attendance_id, :user_id], unique: true, name: "index_on_user_attendance"
end
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe CourseAttendanceGroup, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe CourseAttendance, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe CourseMemberAttendance, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end
Loading…
Cancel
Save