from_scratch
Wojciech Todryk 2011-07-27 20:34:30 +02:00
parent f81c1d69c5
commit 37f548ce46
89 changed files with 466 additions and 70 deletions

0
.gitignore vendored Normal file → Executable file
View File

0
Gemfile.lock Normal file → Executable file
View File

0
Rakefile Normal file → Executable file
View File

4
app/controllers/application_controller.rb Normal file → Executable file
View File

@ -39,4 +39,8 @@ class ApplicationController < ActionController::Base
end
end
def selected_folder
session[:selected_folder] ? @selected_folder = session[:selected_folder] : @selected_folder = $defaults['imap_inbox_folder']
end
end

11
app/controllers/internal_controller.rb Normal file → Executable file
View File

@ -4,9 +4,16 @@ class InternalController < ApplicationController
layout "simple"
def error
@title = t(:general_error)
@title = params[:title] || t(:general_error)
@error = params[:error] || t(:unspecified_error)
logger.error @error
logger.error "!!! InternalControllerError: " + @error
end
def imaperror
@title = t(:imap_error)
@error = params[:error] || t(:unspecified_error)
logger.error "!!! InternalControllerImapError: " + @error
render 'error'
end
end

27
app/controllers/messages_controller.rb Normal file → Executable file
View File

@ -1,14 +1,33 @@
require 'imap_utils'
require 'imap_session'
require 'imap_mailbox'
class MessagesController < ApplicationController
include ImapUtils
include ImapMailboxModule
include ImapSessionModule
before_filter :check_current_user ,:selected_folder
before_filter :open_imap_session, :only => :refresh
after_filter :close_imap_session, :only => :refresh
before_filter :check_current_user, :info
theme :theme_resolver
def index
logger.info "YYYYYYYYYYYYY #{@m.inspect}"
@folders = @current_user.folders.order("name asc")
@current_folder = @current_user.folders.current(@selected_folder)
end
def refresh
@current_user.folders.destroy_all
folders=@mailbox.folders
Folder.createBulk(@current_user,folders)
redirect_to :action => 'index'
end
def folder
session[:selected_folder] = params[:id]
redirect_to :action => 'index'
end
end

9
app/controllers/user_controller.rb Normal file → Executable file
View File

@ -15,7 +15,7 @@ class UserController < ApplicationController
def authenticate
user = User.find_by_email(params[:user][:email])
if user.nil?
redirect_to :action => 'unknown'
redirect_to :action => 'unknown' ,:email=> params[:user][:email]
else
auten = true
if auten == true
@ -26,7 +26,7 @@ class UserController < ApplicationController
redirect_to(session["return_to"])
session["return_to"] = nil
else
redirect_to :controller=> "messages", :action=>"index"
redirect_to :controller=> 'messages', :action=> 'refresh'
end
@ -49,12 +49,15 @@ class UserController < ApplicationController
end
def create
@user = User.new
@server = Server.new
@user.email = params["user_email"]
@user.first_name = params["user_first_name"]
@user.last_name = params["user_last_name"]
@server = Server.new
@server.name = params["server_name"]
if @user.valid? and @server.valid?
@user.save
@server.user_id = @user.id

4
app/helpers/application_helper.rb Normal file → Executable file
View File

@ -1,6 +1,6 @@
module ApplicationHelper
def form_field(object,field,flabel,example)
def form_field(object,field,flabel,example,val)
html = ""
html << "<div class=\"group\">"
@ -24,7 +24,7 @@ def form_field(object,field,flabel,example)
html << "<input name=\""
html << object.class.name.downcase+"_"+field
html << "\" type=\"text\" class=\"text_field\" value=\""
value = object.instance_eval(field) || ""
value = object.instance_eval(field) || val || ""
html << value
html << "\"/>"
html << "<span class=\"description\">"

0
app/helpers/internal_helper.rb Normal file → Executable file
View File

16
app/helpers/messages_helper.rb Normal file → Executable file
View File

@ -1,2 +1,18 @@
module MessagesHelper
def folder_link(folder)
folder.parent.empty? ? name = folder.name : name = folder.parent.gsub(/\./,'#') + "#" + folder.name
s = link_to folder.name.capitalize, :controller => 'messages', :action => 'folder', :id => name
if !folder.unseen.zero?
s += ' (' + folder.unseen.to_s + ')'
end
s
end
def pretty_folder_name(folder)
#folder = folder.gsub(/#/,".")
folder.name.capitalize
end
end

0
app/helpers/user_helper.rb Normal file → Executable file
View File

41
app/models/folder.rb Executable file
View File

@ -0,0 +1,41 @@
class Folder < ActiveRecord::Base
belongs_to :user
validates_presence_of :name, :on => :create
before_save :check_fill_params, :on => :create
private
def check_fill_params
self.messages.nil? ? self.messages = 0 : self.messages
self.unseen.nil? ? self.unseen = 0 : self.unseen
self.msgs_updated_at.nil? ? self.msgs_updated_at = (DateTime.now-1) : self.msgs_updated_at
end
def self.createBulk(user,imapFolders)
imapFolders.each do |name,data|
data.attribs.find_index(:Haschildren).nil? ? has_children = 0 : has_children = 1
name_fields = name.split(data.delim)
if name_fields.count > 1
name = name_fields.delete_at(name_fields.size - 1)
parent = name_fields.join(data.delim)
else
name = name_fields[0]
parent = ""
end
user.folders.create(:name=>name,:parent=>parent,:haschildren=>has_children,:delim=>data.delim,:messages => data.messages,:unseen => data.unseen)
end
end
def self.current(data)
folder = data.split("#")
if folder.size > 1
where(['name = ? and parent = ?',folder[1],folder[0]]).first
else
where(['name = ?',folder[0]]).first
end
end
end

2
app/models/message.rb Executable file
View File

@ -0,0 +1,2 @@
class Message < ActiveRecord::Base
end

0
app/models/prefs.rb Normal file → Executable file
View File

14
app/models/server.rb Normal file → Executable file
View File

@ -1,4 +1,18 @@
class Server < ActiveRecord::Base
validates_presence_of :name
belongs_to :user
before_save :fill_params
def self.primary
first
end
private
def fill_params
self.port = $defaults['imap_port']
$defaults['imap_use_ssl'] == true ? self.use_ssl = 1 : self.use_ssl = 0
end
end

3
app/models/user.rb Normal file → Executable file
View File

@ -1,11 +1,12 @@
require 'ezcrypto'
class User < ActiveRecord::Base
validates_presence_of :email, :on => :create
validates_presence_of :first_name,:last_name
validates_uniqueness_of :email
has_many :servers, :dependent => :destroy
has_one :prefs, :dependent => :destroy
has_many :folders, :dependent => :destroy
def set_cached_password(session,password)
if $defaults['session_encryption']

View File

@ -1,2 +0,0 @@
<h1>Messages#index</h1>
<p>Find me in app/views/messages/index.html.erb</p>

0
config.ru Normal file → Executable file
View File

0
config/application.rb Normal file → Executable file
View File

0
config/boot.rb Normal file → Executable file
View File

7
config/defaults.yml Normal file → Executable file
View File

@ -1,8 +1,15 @@
theme: olive
locale: en
msgs_per_page: 20
msgs_refresh_time: 300
msg_send_type: html
imap_debug: true
imap_use_ssl: 'false'
imap_port: 143
imap_ssl_port: 993
imap_bye_timeout_retry_seconds: 2
imap_inbox_folder: inbox
session_encryption: true
session_password: asDD3s2@sAdc983#

0
config/environment.rb Normal file → Executable file
View File

0
config/environments/development.rb Normal file → Executable file
View File

0
config/environments/production.rb Normal file → Executable file
View File

0
config/environments/test.rb Normal file → Executable file
View File

0
config/initializers/backtrace_silencers.rb Normal file → Executable file
View File

0
config/initializers/inflections.rb Normal file → Executable file
View File

0
config/initializers/mime_types.rb Normal file → Executable file
View File

0
config/initializers/secret_token.rb Normal file → Executable file
View File

0
config/initializers/session_store.rb Normal file → Executable file
View File

View File

@ -78,3 +78,4 @@ en:
login_failure: Login failure. Bad email or password
general_error: General error
unspecified_error: Unspecified error occured
imap_error: Imap Error

6
config/routes.rb Normal file → Executable file
View File

@ -1,15 +1,19 @@
Mailr::Application.routes.draw do
get "internal/error"
post "internal/error"
get "internal/imaperror"
root :to => "messages#index"
get "messages/index"
get "messages/refresh"
match 'messages/folder/:id' => 'messages#folder'
get "user/logout"
post "user/authenticate"
post "user/create"
get "user/login"
get "user/setup"
match 'user/setup/:id' => 'user#setup'
get "user/unknown"
themes_for_rails

0
db/migrate/20110723115402_create_users.rb Normal file → Executable file
View File

0
db/migrate/20110723153214_create_servers.rb Normal file → Executable file
View File

0
db/migrate/20110724125806_create_prefs.rb Normal file → Executable file
View File

0
db/migrate/20110724134917_add_params_to_prefs.rb Normal file → Executable file
View File

View File

@ -0,0 +1,9 @@
class AddUseSslToServers < ActiveRecord::Migration
def self.up
add_column :servers, :use_ssl, :boolean
end
def self.down
remove_column :servers, :use_ssl, :boolean
end
end

View File

@ -0,0 +1,17 @@
class CreateFolders < ActiveRecord::Migration
def self.up
create_table :folders do |t|
t.string :name
t.string :delim
t.string :attribs
t.integer :messages
t.integer :new
t.references :user
t.timestamps
end
end
def self.down
drop_table :folders
end
end

View File

@ -0,0 +1,11 @@
class RenameAttribsInFolders < ActiveRecord::Migration
def self.up
rename_column :folders,:attribs,:haschildren
change_column :folders,:haschildren,:boolean
end
def self.down
change_column :folders,:haschildren,:string
rename_column :folders,:haschildren,:attribs
end
end

View File

@ -0,0 +1,9 @@
class ChangeNewInFolder < ActiveRecord::Migration
def self.up
rename_column :folders,:new,:unseen
end
def self.down
rename_column :folders,:unseen,:new
end
end

View File

@ -0,0 +1,9 @@
class AddColumnToFolder < ActiveRecord::Migration
def self.up
add_column :folders, :parent, :string
end
def self.down
remove_column :folders, :parent
end
end

View File

@ -0,0 +1,9 @@
class AddColumnMsgsToFolder < ActiveRecord::Migration
def self.up
add_column :folders, :msgs_updated_at, :datetime
end
def self.down
remove_column :folders, :msgs_updated_at
end
end

View File

@ -0,0 +1,23 @@
class CreateMessages < ActiveRecord::Migration
def self.up
create_table :messages do |t|
t.integer :folder_id
t.integer :user_id
t.string :msg_id
t.string :from
t.string :to
t.string :subject
t.string :content_type
t.integer :uid
t.integer :size
t.boolean :unread
t.datetime :date
t.timestamps
end
end
def self.down
drop_table :messages
end
end

32
db/schema.rb Normal file → Executable file
View File

@ -10,7 +10,36 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20110724134917) do
ActiveRecord::Schema.define(:version => 20110727134352) do
create_table "folders", :force => true do |t|
t.string "name"
t.string "delim"
t.boolean "haschildren"
t.integer "messages"
t.integer "unseen"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "parent"
t.datetime "msgs_updated_at"
end
create_table "messages", :force => true do |t|
t.integer "folder_id"
t.integer "user_id"
t.string "msg_id"
t.string "from"
t.string "to"
t.string "subject"
t.string "content_type"
t.integer "uid"
t.integer "size"
t.boolean "unread"
t.datetime "date"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "prefs", :force => true do |t|
t.string "theme"
@ -28,6 +57,7 @@ ActiveRecord::Schema.define(:version => 20110724134917) do
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "use_ssl"
end
create_table "users", :force => true do |t|

0
db/seeds.rb Normal file → Executable file
View File

0
doc/README_FOR_APP Normal file → Executable file
View File

23
lib/imap_folder.rb Executable file
View File

@ -0,0 +1,23 @@
require 'net/imap'
module ImapFolderModule
class IMAPFolder
attr_reader :utf7_name
attr_reader :delim
attr_reader :attribs
attr_reader :name
attr_accessor :messages
attr_accessor :unseen
def initialize(utf7_name,delim,attribs)
@utf7_name = utf7_name
@name = Net::IMAP.decode_utf7 utf7_name
@delim = delim
@attribs = attribs
end
end
end

77
lib/imap_mailbox.rb Executable file
View File

@ -0,0 +1,77 @@
require 'net/imap'
require 'imap_folder'
module ImapMailboxModule
class IMAPError < RuntimeError
end
class IMAPMailbox
attr_reader :connected
attr_accessor :selected_folder
attr_accessor :logger
def initialize(logger)
@selected_folder = ''
@folders = {}
@connected = false
@logger = logger
end
def connect(server,username,password)
server_name = server.name
server_port = server.port
server_use_ssl = server.use_ssl
unless @connected
begin
@imap = Net::IMAP.new(server_name, server_port, server_use_ssl)
rescue Net::IMAP::ByeResponseError => bye
begin
System.sleep($defaults['imap_bye_timeout_retry_seconds'])
@imap = Net::IMAP.new(server_name, server_port, server_use_ssl)
rescue Exception => ex
raise IMAPError, ex.inspect
end
rescue Exception => ex
raise IMAPError, ex.inspect
end
@username = username
begin
@imap.login(username, password)
@connected = true
rescue Exception => ex
raise IMAPError, ex.inspect
end
end
end
def disconnect
if @connected
@imap.logout
@imap.disconnect
@imap = nil
@connected = false
end
end
def folders
@folders = {}
folders = @imap.list('', '*')
if folders
folders.each do |f|
folder = ImapFolderModule::IMAPFolder.new(f.name,f.delim,f.attr)
status = @imap.status(folder.name, ["MESSAGES", "UNSEEN"])
folder.messages = status["MESSAGES"]
folder.unseen = status["UNSEEN"]
@folders[folder.name] = folder
end
end
@folders
end
end
end

5
lib/imap_message.rb Executable file
View File

@ -0,0 +1,5 @@
require 'net/imap'
module ImapMessageModule
end

21
lib/imap_session.rb Executable file
View File

@ -0,0 +1,21 @@
require 'net/imap'
require 'imap_mailbox'
module ImapSessionModule
def open_imap_session
begin
@mailbox = ImapMailboxModule::IMAPMailbox.new(logger)
@mailbox.connect(@current_user.servers.primary,@current_user.email, @current_user.get_cached_password(session))
rescue Exception => ex
redirect_to :controller => 'internal', :action => 'imaperror' , :error => ex.inspect
end
end
def close_imap_session
return if @mailbox.nil? or not(@mailbox.connected)
@mailbox.disconnect
@mailbox = nil
end
end

View File

@ -1,48 +0,0 @@
require 'net/imap'
module ImapUtils
class IMAPMailbox
#
# attr_reader :connected
# attr_accessor :selected_mailbox
# cattr_accessor :logger
#
def initialize(logger)
# @selected_mailbox = ''
# @folders = {}
# @connected = false
@logger = logger
@logger.info "XXXXXXXXXX i am in"
end
#
end
def info
@m = IMAPMailbox.new(logger)
logger.info "XXXXXXXXXXXXX"
logger.info @m.inspect
end
#
#def load_imap_session
# begin
# @mailbox = IMAPMailbox.new(self.logger)
## uname = (get_mail_prefs.check_external_mail == 1 ? user.email : user.local_email)
## upass = get_upass
## @mailbox.connect(uname, upass)
## load_folders
# rescue Exception => ex
# render :controller => "internal", :action => "error" , :error => ex.inspect
# end
#end
# def close_imap_session
# return if @mailbox.nil? or not(@mailbox.connected)
# @mailbox.disconnect
# @mailbox = nil
# end
end

0
lib/tasks/.gitkeep Normal file → Executable file
View File

0
public/404.html Normal file → Executable file
View File

0
public/422.html Normal file → Executable file
View File

0
public/500.html Normal file → Executable file
View File

0
public/favicon.ico Normal file → Executable file
View File

0
public/images/rails.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

0
public/javascripts/application.js Normal file → Executable file
View File

0
public/javascripts/controls.js vendored Normal file → Executable file
View File

0
public/javascripts/dragdrop.js vendored Normal file → Executable file
View File

0
public/javascripts/effects.js vendored Normal file → Executable file
View File

0
public/javascripts/prototype.js vendored Normal file → Executable file
View File

0
public/javascripts/rails.js Normal file → Executable file
View File

0
public/robots.txt Normal file → Executable file
View File

0
public/stylesheets/.gitkeep Normal file → Executable file
View File

15
test/fixtures/folders.yml vendored Executable file
View File

@ -0,0 +1,15 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
one:
name: MyString
delim: MyString
attribs: MyString
messages: 1
new: 1
two:
name: MyString
delim: MyString
attribs: MyString
messages: 1
new: 1

27
test/fixtures/messages.yml vendored Executable file
View File

@ -0,0 +1,27 @@
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
one:
folder_id: 1
user_id: 1
msg_id: MyString
from: MyString
to: MyString
subject: MyString
content_type: MyString
uid: 1
size: 1
unread: false
date: 2011-07-27 15:43:52
two:
folder_id: 1
user_id: 1
msg_id: MyString
from: MyString
to: MyString
subject: MyString
content_type: MyString
uid: 1
size: 1
unread: false
date: 2011-07-27 15:43:52

0
test/fixtures/prefs.yml vendored Normal file → Executable file
View File

0
test/fixtures/servers.yml vendored Normal file → Executable file
View File

0
test/fixtures/users.yml vendored Normal file → Executable file
View File

0
test/functional/core_controller_test.rb Normal file → Executable file
View File

0
test/functional/internal_controller_test.rb Normal file → Executable file
View File

0
test/functional/messages_controller_test.rb Normal file → Executable file
View File

0
test/performance/browsing_test.rb Normal file → Executable file
View File

0
test/test_helper.rb Normal file → Executable file
View File

8
test/unit/folder_test.rb Executable file
View File

@ -0,0 +1,8 @@
require 'test_helper'
class FolderTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

0
test/unit/helpers/core_helper_test.rb Normal file → Executable file
View File

0
test/unit/helpers/internal_helper_test.rb Normal file → Executable file
View File

0
test/unit/helpers/messages_helper_test.rb Normal file → Executable file
View File

8
test/unit/message_test.rb Executable file
View File

@ -0,0 +1,8 @@
require 'test_helper'
class MessageTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
end

0
test/unit/prefs_test.rb Normal file → Executable file
View File

0
test/unit/server_test.rb Normal file → Executable file
View File

0
test/unit/user_test.rb Normal file → Executable file
View File

0
themes/olive/images/tick.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 537 B

After

Width:  |  Height:  |  Size: 537 B

2
themes/olive/views/internal/error.html.erb Normal file → Executable file
View File

@ -8,7 +8,7 @@
</div>
<h2><%= @title %></h2>
<div class="content">
<div class="flash"><div class="message error"><p><%= @description %></p></div></div>
<div class="flash"><div class="message error"><p><%= @error %></p></div></div>
</div>
</div>
</div>

View File

@ -0,0 +1,26 @@
<%= link_to t(:refresh), :controller => 'messages', :action => 'refresh' %>
<h1>Current: <%= pretty_folder_name(@current_folder) %></h1>
<%= @current_folder.inspect %>
<%= Time.now - @current_folder.msgs_updated_at %>
<h1>Folders</h1>
<% if @folders.size.zero? %>
No folders.
<% else %>
<ul class="folders">
<% @folders.each do |f|%>
<% if @selected_folder.upcase == f.name.upcase %>
<li class="selected"><%= folder_link(f) %></li>
<% else %>
<li><%= folder_link(f) %></li>
<% end %>
<% end %>
</ul>
<% end %>
<%= link_to t(:logout), :controller => 'user', :action => 'logout' %>

View File

@ -9,10 +9,10 @@
<h2><%= t(:setup_title) %></h2>
<div class="content">
<form action="<%=url_for(:controller => 'user', :action => 'create')%>" method="post" class="form">
<%= raw form_field(@user,"email",nil,"joe.doe@domain.domain") %>
<%= raw form_field(@user,"first_name",nil,"Joe") %>
<%= raw form_field(@user,"last_name",nil,"Doe") %>
<%= raw form_field(@server,"name","server_name","domain.domain") %>
<%= raw form_field(@user,"email",nil,"joe.doe@domain.domain",params['email']) %>
<%= raw form_field(@user,"first_name",nil,"Joe","") %>
<%= raw form_field(@user,"last_name",nil,"Doe","") %>
<%= raw form_field(@server,"name","server_name","domain.domain","") %>
<%= raw form_button("send") %>
</form>
</div>

View File

@ -10,7 +10,7 @@
<div class="content">
<div class="flash"><div class="message warning"><p><%= t(:unknown_user_flash) %></p></div></div>
<p><%= t(:unknown_user_login) %> -> <%= link_to "Login",:controller => "user",:action =>"login" %></p>
<p><%= t(:unknown_user_setup) %> -> <%= link_to "Setup",:controller => "user",:action => "setup" %></p>
<p><%= t(:unknown_user_setup) %> -> <%= link_to "Setup",:controller => "user",:action => "setup",:email => params['email'] %></p>
</div>
</div>
</div>

0
vendor/plugins/.gitkeep vendored Normal file → Executable file
View File