Description:
add load button add more admin authorization
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r711:a65ea018c51c - - 2 files changed: 26 inserted, 1 deleted

@@ -1,210 +1,213
1 require 'net/smtp'
1 require 'net/smtp'
2
2
3 class UsersController < ApplicationController
3 class UsersController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_filter :authenticate, :except => [:new,
7 before_filter :authenticate, :except => [:new,
8 :register,
8 :register,
9 :confirm,
9 :confirm,
10 :forget,
10 :forget,
11 :retrieve_password]
11 :retrieve_password]
12
12
13 before_filter :verify_online_registration, :only => [:new,
13 before_filter :verify_online_registration, :only => [:new,
14 :register,
14 :register,
15 :forget,
15 :forget,
16 :retrieve_password]
16 :retrieve_password]
17 before_filter :authenticate, :profile_authorization, only: [:profile]
17 before_filter :authenticate, :profile_authorization, only: [:profile]
18
18
19 + before_filter :admin_authorization, only: [:stat, :toggle_activate, :toggle_enable]
20 +
21 +
19 verify :method => :post, :only => [:chg_passwd],
22 verify :method => :post, :only => [:chg_passwd],
20 :redirect_to => { :action => :index }
23 :redirect_to => { :action => :index }
21
24
22 #in_place_edit_for :user, :alias_for_editing
25 #in_place_edit_for :user, :alias_for_editing
23 #in_place_edit_for :user, :email_for_editing
26 #in_place_edit_for :user, :email_for_editing
24
27
25 def index
28 def index
26 if !GraderConfiguration['system.user_setting_enabled']
29 if !GraderConfiguration['system.user_setting_enabled']
27 redirect_to :controller => 'main', :action => 'list'
30 redirect_to :controller => 'main', :action => 'list'
28 else
31 else
29 @user = User.find(session[:user_id])
32 @user = User.find(session[:user_id])
30 end
33 end
31 end
34 end
32
35
33 def chg_passwd
36 def chg_passwd
34 user = User.find(session[:user_id])
37 user = User.find(session[:user_id])
35 user.password = params[:passwd]
38 user.password = params[:passwd]
36 user.password_confirmation = params[:passwd_verify]
39 user.password_confirmation = params[:passwd_verify]
37 if user.save
40 if user.save
38 flash[:notice] = 'password changed'
41 flash[:notice] = 'password changed'
39 else
42 else
40 flash[:notice] = 'Error: password changing failed'
43 flash[:notice] = 'Error: password changing failed'
41 end
44 end
42 redirect_to :action => 'index'
45 redirect_to :action => 'index'
43 end
46 end
44
47
45 def new
48 def new
46 @user = User.new
49 @user = User.new
47 render :action => 'new', :layout => 'empty'
50 render :action => 'new', :layout => 'empty'
48 end
51 end
49
52
50 def register
53 def register
51 if(params[:cancel])
54 if(params[:cancel])
52 redirect_to :controller => 'main', :action => 'login'
55 redirect_to :controller => 'main', :action => 'login'
53 return
56 return
54 end
57 end
55 @user = User.new(user_params)
58 @user = User.new(user_params)
56 @user.password_confirmation = @user.password = User.random_password
59 @user.password_confirmation = @user.password = User.random_password
57 @user.activated = false
60 @user.activated = false
58 if (@user.valid?) and (@user.save)
61 if (@user.valid?) and (@user.save)
59 if send_confirmation_email(@user)
62 if send_confirmation_email(@user)
60 render :action => 'new_splash', :layout => 'empty'
63 render :action => 'new_splash', :layout => 'empty'
61 else
64 else
62 @admin_email = GraderConfiguration['system.admin_email']
65 @admin_email = GraderConfiguration['system.admin_email']
63 render :action => 'email_error', :layout => 'empty'
66 render :action => 'email_error', :layout => 'empty'
64 end
67 end
65 else
68 else
66 @user.errors.add(:base,"Email cannot be blank") if @user.email==''
69 @user.errors.add(:base,"Email cannot be blank") if @user.email==''
67 render :action => 'new', :layout => 'empty'
70 render :action => 'new', :layout => 'empty'
68 end
71 end
69 end
72 end
70
73
71 def confirm
74 def confirm
72 login = params[:login]
75 login = params[:login]
73 key = params[:activation]
76 key = params[:activation]
74 @user = User.find_by_login(login)
77 @user = User.find_by_login(login)
75 if (@user) and (@user.verify_activation_key(key))
78 if (@user) and (@user.verify_activation_key(key))
76 if @user.valid? # check uniquenss of email
79 if @user.valid? # check uniquenss of email
77 @user.activated = true
80 @user.activated = true
78 @user.save
81 @user.save
79 @result = :successful
82 @result = :successful
80 else
83 else
81 @result = :email_used
84 @result = :email_used
82 end
85 end
83 else
86 else
84 @result = :failed
87 @result = :failed
85 end
88 end
86 render :action => 'confirm', :layout => 'empty'
89 render :action => 'confirm', :layout => 'empty'
87 end
90 end
88
91
89 def forget
92 def forget
90 render :action => 'forget', :layout => 'empty'
93 render :action => 'forget', :layout => 'empty'
91 end
94 end
92
95
93 def retrieve_password
96 def retrieve_password
94 email = params[:email]
97 email = params[:email]
95 user = User.find_by_email(email)
98 user = User.find_by_email(email)
96 if user
99 if user
97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
100 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
98 if last_updated_time > Time.now.gmtime - 5.minutes
101 if last_updated_time > Time.now.gmtime - 5.minutes
99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
102 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
100 else
103 else
101 user.password = user.password_confirmation = User.random_password
104 user.password = user.password_confirmation = User.random_password
102 user.save
105 user.save
103 send_new_password_email(user)
106 send_new_password_email(user)
104 flash[:notice] = 'New password has been mailed to you.'
107 flash[:notice] = 'New password has been mailed to you.'
105 end
108 end
106 else
109 else
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
110 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
108 end
111 end
109 redirect_to :action => 'forget'
112 redirect_to :action => 'forget'
110 end
113 end
111
114
112 def stat
115 def stat
113 @user = User.find(params[:id])
116 @user = User.find(params[:id])
114 @submission = Submission.joins(:problem).where(user_id: params[:id])
117 @submission = Submission.joins(:problem).where(user_id: params[:id])
115 @submission = @submission.where('problems.available = true') unless current_user.admin?
118 @submission = @submission.where('problems.available = true') unless current_user.admin?
116
119
117 range = 120
120 range = 120
118 @histogram = { data: Array.new(range,0), summary: {} }
121 @histogram = { data: Array.new(range,0), summary: {} }
119 @summary = {count: 0, solve: 0, attempt: 0}
122 @summary = {count: 0, solve: 0, attempt: 0}
120 problem = Hash.new(0)
123 problem = Hash.new(0)
121
124
122 @submission.find_each do |sub|
125 @submission.find_each do |sub|
123 #histogram
126 #histogram
124 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
127 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
125 @histogram[:data][d.to_i] += 1 if d < range
128 @histogram[:data][d.to_i] += 1 if d < range
126
129
127 @summary[:count] += 1
130 @summary[:count] += 1
128 next unless sub.problem
131 next unless sub.problem
129 problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max
132 problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max
130 end
133 end
131
134
132 @histogram[:summary][:max] = [@histogram[:data].max,1].max
135 @histogram[:summary][:max] = [@histogram[:data].max,1].max
133 @summary[:attempt] = problem.count
136 @summary[:attempt] = problem.count
134 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
137 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
135 end
138 end
136
139
137 def toggle_activate
140 def toggle_activate
138 @user = User.find(params[:id])
141 @user = User.find(params[:id])
139 @user.update_attributes( activated: !@user.activated? )
142 @user.update_attributes( activated: !@user.activated? )
140 respond_to do |format|
143 respond_to do |format|
141 format.js { render partial: 'toggle_button',
144 format.js { render partial: 'toggle_button',
142 locals: {button_id: "#toggle_activate_user_#{@user.id}",button_on: @user.activated? } }
145 locals: {button_id: "#toggle_activate_user_#{@user.id}",button_on: @user.activated? } }
143 end
146 end
144 end
147 end
145
148
146 def toggle_enable
149 def toggle_enable
147 @user = User.find(params[:id])
150 @user = User.find(params[:id])
148 @user.update_attributes( enabled: !@user.enabled? )
151 @user.update_attributes( enabled: !@user.enabled? )
149 respond_to do |format|
152 respond_to do |format|
150 format.js { render partial: 'toggle_button',
153 format.js { render partial: 'toggle_button',
151 locals: {button_id: "#toggle_enable_user_#{@user.id}",button_on: @user.enabled? } }
154 locals: {button_id: "#toggle_enable_user_#{@user.id}",button_on: @user.enabled? } }
152 end
155 end
153 end
156 end
154
157
155 protected
158 protected
156
159
157 def verify_online_registration
160 def verify_online_registration
158 if !GraderConfiguration['system.online_registration']
161 if !GraderConfiguration['system.online_registration']
159 redirect_to :controller => 'main', :action => 'login'
162 redirect_to :controller => 'main', :action => 'login'
160 end
163 end
161 end
164 end
162
165
163 def send_confirmation_email(user)
166 def send_confirmation_email(user)
164 contest_name = GraderConfiguration['contest.name']
167 contest_name = GraderConfiguration['contest.name']
165 activation_url = url_for(:action => 'confirm',
168 activation_url = url_for(:action => 'confirm',
166 :login => user.login,
169 :login => user.login,
167 :activation => user.activation_key)
170 :activation => user.activation_key)
168 home_url = url_for(:controller => 'main', :action => 'index')
171 home_url = url_for(:controller => 'main', :action => 'index')
169 mail_subject = "[#{contest_name}] Confirmation"
172 mail_subject = "[#{contest_name}] Confirmation"
170 mail_body = t('registration.email_body', {
173 mail_body = t('registration.email_body', {
171 :full_name => user.full_name,
174 :full_name => user.full_name,
172 :contest_name => contest_name,
175 :contest_name => contest_name,
173 :login => user.login,
176 :login => user.login,
174 :password => user.password,
177 :password => user.password,
175 :activation_url => activation_url,
178 :activation_url => activation_url,
176 :admin_email => GraderConfiguration['system.admin_email']
179 :admin_email => GraderConfiguration['system.admin_email']
177 })
180 })
178
181
179 logger.info mail_body
182 logger.info mail_body
180
183
181 send_mail(user.email, mail_subject, mail_body)
184 send_mail(user.email, mail_subject, mail_body)
182 end
185 end
183
186
184 def send_new_password_email(user)
187 def send_new_password_email(user)
185 contest_name = GraderConfiguration['contest.name']
188 contest_name = GraderConfiguration['contest.name']
186 mail_subject = "[#{contest_name}] Password recovery"
189 mail_subject = "[#{contest_name}] Password recovery"
187 mail_body = t('registration.password_retrieval.email_body', {
190 mail_body = t('registration.password_retrieval.email_body', {
188 :full_name => user.full_name,
191 :full_name => user.full_name,
189 :contest_name => contest_name,
192 :contest_name => contest_name,
190 :login => user.login,
193 :login => user.login,
191 :password => user.password,
194 :password => user.password,
192 :admin_email => GraderConfiguration['system.admin_email']
195 :admin_email => GraderConfiguration['system.admin_email']
193 })
196 })
194
197
195 logger.info mail_body
198 logger.info mail_body
196
199
197 send_mail(user.email, mail_subject, mail_body)
200 send_mail(user.email, mail_subject, mail_body)
198 end
201 end
199
202
200 # allow viewing of regular user profile only when options allow so
203 # allow viewing of regular user profile only when options allow so
201 # only admins can view admins profile
204 # only admins can view admins profile
202 def profile_authorization
205 def profile_authorization
203 #if view admins' profile, allow only admin
206 #if view admins' profile, allow only admin
204 return false unless(params[:id])
207 return false unless(params[:id])
205 user = User.find(params[:id])
208 user = User.find(params[:id])
206 return false unless user
209 return false unless user
207 return admin_authorization if user.admin?
210 return admin_authorization if user.admin?
208 return true if GraderConfiguration["right.user_view_submission"]
211 return true if GraderConfiguration["right.user_view_submission"]
209
212
210 #finally, we allow only admin
213 #finally, we allow only admin
@@ -1,248 +1,270
1 %h2 Live submit
1 %h2 Live submit
2 %br
2 %br
3
3
4 %textarea#text_sourcecode{style: "display:none"}~ @source
4 %textarea#text_sourcecode{style: "display:none"}~ @source
5 .container
5 .container
6 .row
6 .row
7 .col-md-12
7 .col-md-12
8 .alert.alert-info
8 .alert.alert-info
9 Write your code in the following box, choose language, and click submit button when finished
9 Write your code in the following box, choose language, and click submit button when finished
10 .row
10 .row
11 .col-md-8
11 .col-md-8
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 .col-md-4
13 .col-md-4
14 - # submission form
14 - # submission form
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
16
16
17 = hidden_field_tag 'editor_text', @source
17 = hidden_field_tag 'editor_text', @source
18 = hidden_field_tag 'submission[problem_id]', @problem.id
18 = hidden_field_tag 'submission[problem_id]', @problem.id
19 .form-group
19 .form-group
20 = label_tag "Task:"
20 = label_tag "Task:"
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
22 .form-group
22 .form-group
23 = label_tag "Description:"
23 = label_tag "Description:"
24 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
24 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
25
25
26 .form-group
26 .form-group
27 = label_tag 'Language:'
27 = label_tag 'Language:'
28 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
28 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
29 .form-group
29 .form-group
30 + .input-group
31 + %span.input-group-btn
32 + %span.btn.btn-default.btn-file
33 + Browse
34 + = file_field_tag 'load_file'
35 + = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
36 + .form-group
30 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
37 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
31 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
38 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
32 - # latest submission status
39 - # latest submission status
33 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
40 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
34 .panel-heading
41 .panel-heading
35 Latest Submission Status
42 Latest Submission Status
36 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
43 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
37 .panel-body
44 .panel-body
38 %div#latest_status
45 %div#latest_status
39 - if @submission
46 - if @submission
40 = render :partial => 'submission_short',
47 = render :partial => 'submission_short',
41 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
48 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
42 .row
49 .row
43 .col-md-12
50 .col-md-12
44 %h2 Console
51 %h2 Console
45 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
46
53
47 :javascript
54 :javascript
48 $(document).ready(function() {
55 $(document).ready(function() {
49 e = ace.edit("editor")
56 e = ace.edit("editor")
50 e.setValue($("#text_sourcecode").val());
57 e.setValue($("#text_sourcecode").val());
51 e.gotoLine(1);
58 e.gotoLine(1);
52 $("#language_id").trigger('change');
59 $("#language_id").trigger('change');
53 - brython();
60 +
61 + $("#load_file").on('change',function(evt) {
62 + var file = evt.target.files[0];
63 + var reader = new FileReader();
64 + reader.onload = function(theFile) {
65 + var e = ace.edit("editor")
66 + e.setValue(theFile.target.result);
67 + e.gotoLine(1);
68 + };
69 + reader.readAsText(file)
70 + });
71 +
72 + //brython();
54 });
73 });
55
74
56
75
76 +
77 +
78 +
57 %script#__main__{type:'text/python3'}
79 %script#__main__{type:'text/python3'}
58 :plain
80 :plain
59 import sys
81 import sys
60 import traceback
82 import traceback
61
83
62 from browser import document as doc
84 from browser import document as doc
63 from browser import window, alert, console
85 from browser import window, alert, console
64
86
65 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
87 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
66 for supporting Python development. See www.python.org for more information."""
88 for supporting Python development. See www.python.org for more information."""
67
89
68 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
90 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
69 All Rights Reserved.
91 All Rights Reserved.
70
92
71 Copyright (c) 2001-2013 Python Software Foundation.
93 Copyright (c) 2001-2013 Python Software Foundation.
72 All Rights Reserved.
94 All Rights Reserved.
73
95
74 Copyright (c) 2000 BeOpen.com.
96 Copyright (c) 2000 BeOpen.com.
75 All Rights Reserved.
97 All Rights Reserved.
76
98
77 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
99 Copyright (c) 1995-2001 Corporation for National Research Initiatives.
78 All Rights Reserved.
100 All Rights Reserved.
79
101
80 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
102 Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
81 All Rights Reserved."""
103 All Rights Reserved."""
82
104
83 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
105 _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
84 All rights reserved.
106 All rights reserved.
85
107
86 Redistribution and use in source and binary forms, with or without
108 Redistribution and use in source and binary forms, with or without
87 modification, are permitted provided that the following conditions are met:
109 modification, are permitted provided that the following conditions are met:
88
110
89 Redistributions of source code must retain the above copyright notice, this
111 Redistributions of source code must retain the above copyright notice, this
90 list of conditions and the following disclaimer. Redistributions in binary
112 list of conditions and the following disclaimer. Redistributions in binary
91 form must reproduce the above copyright notice, this list of conditions and
113 form must reproduce the above copyright notice, this list of conditions and
92 the following disclaimer in the documentation and/or other materials provided
114 the following disclaimer in the documentation and/or other materials provided
93 with the distribution.
115 with the distribution.
94 Neither the name of the <ORGANIZATION> nor the names of its contributors may
116 Neither the name of the <ORGANIZATION> nor the names of its contributors may
95 be used to endorse or promote products derived from this software without
117 be used to endorse or promote products derived from this software without
96 specific prior written permission.
118 specific prior written permission.
97
119
98 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
120 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
99 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
121 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
100 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
122 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
101 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
123 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
102 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
124 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
103 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
125 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
104 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
126 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
105 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
127 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
106 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
128 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
107 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
129 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
108 POSSIBILITY OF SUCH DAMAGE.
130 POSSIBILITY OF SUCH DAMAGE.
109 """
131 """
110
132
111 def credits():
133 def credits():
112 print(_credits)
134 print(_credits)
113 credits.__repr__ = lambda:_credits
135 credits.__repr__ = lambda:_credits
114
136
115 def copyright():
137 def copyright():
116 print(_copyright)
138 print(_copyright)
117 copyright.__repr__ = lambda:_copyright
139 copyright.__repr__ = lambda:_copyright
118
140
119 def license():
141 def license():
120 print(_license)
142 print(_license)
121 license.__repr__ = lambda:_license
143 license.__repr__ = lambda:_license
122
144
123 def write(data):
145 def write(data):
124 doc['console'].value += str(data)
146 doc['console'].value += str(data)
125
147
126
148
127 sys.stdout.write = sys.stderr.write = write
149 sys.stdout.write = sys.stderr.write = write
128 history = []
150 history = []
129 current = 0
151 current = 0
130 _status = "main" # or "block" if typing inside a block
152 _status = "main" # or "block" if typing inside a block
131
153
132 # execution namespace
154 # execution namespace
133 editor_ns = {'credits':credits,
155 editor_ns = {'credits':credits,
134 'copyright':copyright,
156 'copyright':copyright,
135 'license':license,
157 'license':license,
136 '__name__':'__main__'}
158 '__name__':'__main__'}
137
159
138 def cursorToEnd(*args):
160 def cursorToEnd(*args):
139 pos = len(doc['console'].value)
161 pos = len(doc['console'].value)
140 doc['console'].setSelectionRange(pos, pos)
162 doc['console'].setSelectionRange(pos, pos)
141 doc['console'].scrollTop = doc['console'].scrollHeight
163 doc['console'].scrollTop = doc['console'].scrollHeight
142
164
143 def get_col(area):
165 def get_col(area):
144 # returns the column num of cursor
166 # returns the column num of cursor
145 sel = doc['console'].selectionStart
167 sel = doc['console'].selectionStart
146 lines = doc['console'].value.split('\n')
168 lines = doc['console'].value.split('\n')
147 for line in lines[:-1]:
169 for line in lines[:-1]:
148 sel -= len(line) + 1
170 sel -= len(line) + 1
149 return sel
171 return sel
150
172
151
173
152 def myKeyPress(event):
174 def myKeyPress(event):
153 global _status, current
175 global _status, current
154 if event.keyCode == 9: # tab key
176 if event.keyCode == 9: # tab key
155 event.preventDefault()
177 event.preventDefault()
156 doc['console'].value += " "
178 doc['console'].value += " "
157 elif event.keyCode == 13: # return
179 elif event.keyCode == 13: # return
158 src = doc['console'].value
180 src = doc['console'].value
159 if _status == "main":
181 if _status == "main":
160 currentLine = src[src.rfind('>>>') + 4:]
182 currentLine = src[src.rfind('>>>') + 4:]
161 elif _status == "3string":
183 elif _status == "3string":
162 currentLine = src[src.rfind('>>>') + 4:]
184 currentLine = src[src.rfind('>>>') + 4:]
163 currentLine = currentLine.replace('\n... ', '\n')
185 currentLine = currentLine.replace('\n... ', '\n')
164 else:
186 else:
165 currentLine = src[src.rfind('...') + 4:]
187 currentLine = src[src.rfind('...') + 4:]
166 if _status == 'main' and not currentLine.strip():
188 if _status == 'main' and not currentLine.strip():
167 doc['console'].value += '\n>>> '
189 doc['console'].value += '\n>>> '
168 event.preventDefault()
190 event.preventDefault()
169 return
191 return
170 doc['console'].value += '\n'
192 doc['console'].value += '\n'
171 history.append(currentLine)
193 history.append(currentLine)
172 current = len(history)
194 current = len(history)
173 if _status == "main" or _status == "3string":
195 if _status == "main" or _status == "3string":
174 try:
196 try:
175 _ = editor_ns['_'] = eval(currentLine, editor_ns)
197 _ = editor_ns['_'] = eval(currentLine, editor_ns)
176 if _ is not None:
198 if _ is not None:
177 write(repr(_)+'\n')
199 write(repr(_)+'\n')
178 doc['console'].value += '>>> '
200 doc['console'].value += '>>> '
179 _status = "main"
201 _status = "main"
180 except IndentationError:
202 except IndentationError:
181 doc['console'].value += '... '
203 doc['console'].value += '... '
182 _status = "block"
204 _status = "block"
183 except SyntaxError as msg:
205 except SyntaxError as msg:
184 if str(msg) == 'invalid syntax : triple string end not found' or \
206 if str(msg) == 'invalid syntax : triple string end not found' or \
185 str(msg).startswith('Unbalanced bracket'):
207 str(msg).startswith('Unbalanced bracket'):
186 doc['console'].value += '... '
208 doc['console'].value += '... '
187 _status = "3string"
209 _status = "3string"
188 elif str(msg) == 'eval() argument must be an expression':
210 elif str(msg) == 'eval() argument must be an expression':
189 try:
211 try:
190 exec(currentLine, editor_ns)
212 exec(currentLine, editor_ns)
191 except:
213 except:
192 traceback.print_exc()
214 traceback.print_exc()
193 doc['console'].value += '>>> '
215 doc['console'].value += '>>> '
194 _status = "main"
216 _status = "main"
195 elif str(msg) == 'decorator expects function':
217 elif str(msg) == 'decorator expects function':
196 doc['console'].value += '... '
218 doc['console'].value += '... '
197 _status = "block"
219 _status = "block"
198 else:
220 else:
199 traceback.print_exc()
221 traceback.print_exc()
200 doc['console'].value += '>>> '
222 doc['console'].value += '>>> '
201 _status = "main"
223 _status = "main"
202 except:
224 except:
203 traceback.print_exc()
225 traceback.print_exc()
204 doc['console'].value += '>>> '
226 doc['console'].value += '>>> '
205 _status = "main"
227 _status = "main"
206 elif currentLine == "": # end of block
228 elif currentLine == "": # end of block
207 block = src[src.rfind('>>>') + 4:].splitlines()
229 block = src[src.rfind('>>>') + 4:].splitlines()
208 block = [block[0]] + [b[4:] for b in block[1:]]
230 block = [block[0]] + [b[4:] for b in block[1:]]
209 block_src = '\n'.join(block)
231 block_src = '\n'.join(block)
210 # status must be set before executing code in globals()
232 # status must be set before executing code in globals()
211 _status = "main"
233 _status = "main"
212 try:
234 try:
213 _ = exec(block_src, editor_ns)
235 _ = exec(block_src, editor_ns)
214 if _ is not None:
236 if _ is not None:
215 print(repr(_))
237 print(repr(_))
216 except:
238 except:
217 traceback.print_exc()
239 traceback.print_exc()
218 doc['console'].value += '>>> '
240 doc['console'].value += '>>> '
219 else:
241 else:
220 doc['console'].value += '... '
242 doc['console'].value += '... '
221
243
222 cursorToEnd()
244 cursorToEnd()
223 event.preventDefault()
245 event.preventDefault()
224
246
225 def myKeyDown(event):
247 def myKeyDown(event):
226 global _status, current
248 global _status, current
227 if event.keyCode == 37: # left arrow
249 if event.keyCode == 37: # left arrow
228 sel = get_col(doc['console'])
250 sel = get_col(doc['console'])
229 if sel < 5:
251 if sel < 5:
230 event.preventDefault()
252 event.preventDefault()
231 event.stopPropagation()
253 event.stopPropagation()
232 elif event.keyCode == 36: # line start
254 elif event.keyCode == 36: # line start
233 pos = doc['console'].selectionStart
255 pos = doc['console'].selectionStart
234 col = get_col(doc['console'])
256 col = get_col(doc['console'])
235 doc['console'].setSelectionRange(pos - col + 4, pos - col + 4)
257 doc['console'].setSelectionRange(pos - col + 4, pos - col + 4)
236 event.preventDefault()
258 event.preventDefault()
237 elif event.keyCode == 38: # up
259 elif event.keyCode == 38: # up
238 if current > 0:
260 if current > 0:
239 pos = doc['console'].selectionStart
261 pos = doc['console'].selectionStart
240 col = get_col(doc['console'])
262 col = get_col(doc['console'])
241 # remove current line
263 # remove current line
242 doc['console'].value = doc['console'].value[:pos - col + 4]
264 doc['console'].value = doc['console'].value[:pos - col + 4]
243 current -= 1
265 current -= 1
244 doc['console'].value += history[current]
266 doc['console'].value += history[current]
245 event.preventDefault()
267 event.preventDefault()
246 elif event.keyCode == 40: # down
268 elif event.keyCode == 40: # down
247 if current < len(history) - 1:
269 if current < len(history) - 1:
248 pos = doc['console'].selectionStart
270 pos = doc['console'].selectionStart
You need to be logged in to leave comments. Login now