added user test, basic user methods

This commit is contained in:
Albert Yi
2010-02-06 16:48:40 -05:00
parent 130810e21f
commit 3bfae1f0db
67 changed files with 1350 additions and 282 deletions

26
Gemfile
View File

@@ -1,23 +1,13 @@
# Edit this Gemfile to bundle your application's dependencies. # Edit this Gemfile to bundle your application's dependencies.
source 'http://gemcutter.org' source 'http://gemcutter.org'
## Bundle edge rails:
path "/Users/ayi/Projects/personal/rails3", :glob => "{*/,}*.gemspec"
gem "rails", "3.0.0.beta" gem "rails", "3.0.0.beta"
gem "pg"
gem "memcache-client", :require => "memcache"
# ActiveRecord requires a database adapter. By default, group :test do
# Rails has selected sqlite3. gem "shoulda"
gem "sqlite3-ruby", :require => "sqlite3" gem "factory_girl"
gem "mocha"
## Bundle the gems you use: gem "faker"
# gem "bj" end
# gem "hpricot", "0.6"
# gem "sqlite3-ruby", :require => "sqlite3"
# gem "aws-s3", :require => "aws/s3"
## Bundle gems used only in certain environments:
# gem "rspec", :group => :test
# group :test do
# gem "webrat"
# end

132
INSTALL.debian Normal file
View File

@@ -0,0 +1,132 @@
#!/bin/bash
echo "This script is out of date; please read the INSTALL document"
exit 1
if [ $USER != root ] ; then
echo "You must run this script as root"
exit 1
fi
echo "Danbooru Install"
echo "This script will install Ruby, Rails, PostgreSQL, and Nginx. By the end,"
echo "you should be able to connect to the server and create an account."
echo
echo "It will create a new user called danbooru which will run the Danbooru"
echo "processes. It will download the latest trunk copy and install it in"
echo "/var/www/danbooru. It will run three Mongrel processes, starting on port"
echo "8050."
echo
echo -n "Enter the hostname for this server (ex: danbooru.donmai.us): "
read hostname
if [ -z $hostname ] ; then
echo "Must enter a hostname"
exit 1
fi
echo -n "Enter a name for the site (default: Danbooru): "
read sitename
if [ -z $sitename ] ; then
sitename=Danbooru
fi
# Install packages
apt-get -y install sudo gcc g++ make libreadline5-dev zlib1g-dev flex bison libgd2-noxpm libgd2-noxpm-dev bzip2 postgresql-8.3 postgresql-contrib-8.3 libpq-dev ruby ruby1.8-dev ri irb rdoc rubygems ragel memcached libmemcache-dev subversion nginx rake libopenssl-ruby mongrel
# Install Ruby gems
for i in postgres diff-lcs html5 mongrel mongrel_cluster memcache-client aws-s3 json ; do gem install $i ; done
gem install rails --version=2.1.0
gem install acts_as_versioned
# Create user account
useradd -m danbooru
PG_HBA_FILE="/etc/postgresql/8.3/main/pg_hba.conf"
echo "local all postgres,danbooru trust" > $PG_HBA_FILE
echo "host all postgres,danbooru 127.0.0.1/32 trust" >> $PG_HBA_FILE
/etc/init.d/postgresql-8.3 restart
# Install Danbooru
cd /var/www
svn export svn://donmai.us/danbooru/trunk danbooru
chown -R danbooru:danbooru danbooru
cd danbooru
mkdir -p public/data/sample
cd config
cp database.yml.example database.yml
cp local_config.rb.example local_config.rb
sed -i -e "s/DAN_HOSTNAME/$hostname/g" local_config.rb
sed -i -e "s/DAN_SITENAME/$sitename/g" local_config.rb
echo "--- " > mongrel_cluster.yml
echo "cwd: /var/www/danbooru" >> mongrel_cluster.yml
echo "port: \"8050\"" >> mongrel_cluster.yml
echo "environment: production" >> mongrel_cluster.yml
echo "address: 127.0.0.1" >> mongrel_cluster.yml
echo "servers: 3" >> mongrel_cluster.yml
echo "num_processors: 10" >> mongrel_cluster.yml
cd ../lib/danbooru_image_resizer
ruby extconf.rb
make
cd ../..
sudo -u postgres createuser -s danbooru
sudo -u danbooru createdb danbooru
sudo -u danbooru psql danbooru < db/postgres.sql
sudo -u danbooru rake db:migrate RAILS_ENV=production
script/donmai/upbooru
# Set up nginx
DANBOORU_CONF_FILE="/etc/nginx/sites-enabled/danbooru.conf"
echo "upstream mongrel {" > $DANBOORU_CONF_FILE
echo " server 127.0.0.1:8050;" >> $DANBOORU_CONF_FILE
echo " server 127.0.0.1:8051;" >> $DANBOORU_CONF_FILE
echo " server 127.0.0.1:8052;" >> $DANBOORU_CONF_FILE
echo "}" >> $DANBOORU_CONF_FILE
echo "server {" >> $DANBOORU_CONF_FILE
echo " listen 80;" >> $DANBOORU_CONF_FILE
echo " server_name $hostname;" >> $DANBOORU_CONF_FILE
echo " root /var/www/danbooru/public;" >> $DANBOORU_CONF_FILE
echo " index index.html;" >> $DANBOORU_CONF_FILE
echo " access_log /var/www/danbooru/log/server.access.log;" >> $DANBOORU_CONF_FILE
echo " error_log /var/www/danbooru/log/server.error.log;" >> $DANBOORU_CONF_FILE
echo " client_max_body_size 30m;" >> $DANBOORU_CONF_FILE
echo " location /stylesheets {" >> $DANBOORU_CONF_FILE
echo " expires max;" >> $DANBOORU_CONF_FILE
echo " break;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " location /javascripts {" >> $DANBOORU_CONF_FILE
echo " expires max;" >> $DANBOORU_CONF_FILE
echo " break;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " location /data {" >> $DANBOORU_CONF_FILE
echo " valid_referers none $hostname;" >> $DANBOORU_CONF_FILE
echo " if (\$invalid_referer) {" >> $DANBOORU_CONF_FILE
echo " return 403;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " expires max;" >> $DANBOORU_CONF_FILE
echo " break;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " location /maintenance.html {" >> $DANBOORU_CONF_FILE
echo " expires 10;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " if (-f \$document_root/maintenance.html) {" >> $DANBOORU_CONF_FILE
echo " rewrite ^(.*)\$ /maintenance.html last;" >> $DANBOORU_CONF_FILE
echo " break;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " location / {" >> $DANBOORU_CONF_FILE
echo " proxy_set_header X-Real-IP \$remote_addr;" >> $DANBOORU_CONF_FILE
echo " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;" >> $DANBOORU_CONF_FILE
echo " proxy_set_header Host \$http_host;" >> $DANBOORU_CONF_FILE
echo " proxy_redirect false;" >> $DANBOORU_CONF_FILE
echo " if (!-f \$request_filename) {" >> $DANBOORU_CONF_FILE
echo " proxy_pass http://mongrel;" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " }" >> $DANBOORU_CONF_FILE
echo " error_page 404 /404.html;" >> $DANBOORU_CONF_FILE
echo " error_page 500 502 503 504 /500.html;" >> $DANBOORU_CONF_FILE
echo "}" >> $DANBOORU_CONF_FILE
/etc/init.d/nginx restart
echo
echo "I'm done!"
echo "You should probably set the password for the danbooru account (run passwd danbooru)."

138
INSTALL.freebsd Normal file
View File

@@ -0,0 +1,138 @@
Danbooru Installation guide on FreeBSD (6.2)
Provided by Shuugo
Cleanup of dovac's guide: http://uruchai.com/2007/12/24/in-depth-guide-on-installing-danbooru-on-freebsd
A minimal FreeBSD profile installation is encouraged. You can use VMWare to test how things work before trying on an actual machine.
1)) Updating ports:
You can find how fully work here: http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/ports-using.html but basically you will only need:
1. portsnap fetch
2. portsnap extract
2)) Install the following things through ports
1. cd /usr/ports/devel/mkmf/ && make install clean
2. cd /usr/ports/ftp/wget/ && make install clean
3. cd /usr/ports/editors/nano/ && make install clean
4. cd /usr/ports/devel/subversion/ && make install clean (May ask for configuration: Choose "libiconv", "python25", enable "huge stack size", and disable "ipv6"
5. cd /usr/ports/databases/memcached/ && make install clean
6. cd /usr/ports/graphics/gd/ && make install clean (Make sure you enable iconv support)
7. cd /usr/ports/databases/postgresql83-client/ && make install clean (config defaults are ok)
8. cd /usr/ports/databases/postgresql83-server/ && make install clean (config defaults are ok)
3)) Editing rc.conf for starting postgres and memcached at boot.
1. nano /etc/rc.conf
2. Add the following at the end of the file:
postgresql_enable="YES"
memcached_enable="yes"
memacached_flags="-l 127.0.0.1 -d m 100"
3. Press Control + X to save.
4. We run "/usr/local/etc/rc.d/postgresql initdb" to get ready to initialize postgres for first time.
5. Use "/usr/local/etc/rc.d/postgresql start", to start the postgresql server.
4)) Ruby on rails installation
1. cd /usr/ports/lang/ruby18/ && make install clean (Disable ipv6)
2. rubygem-rails port is broken, download it from rubyforge
2a wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz
2b tar xvf rubygems-1.0.1.tgz
2c cd rubygems-1.0.1
2d ruby setup.rb
3. cd /usr/ports/www/rubygem-rails/ && make install clean (Be sure it's rubygem-rails-1.2.6. Rails 2.0 isn't compatible yet)
4. cd /usr/ports/www/rubygem-redcloth/ && make install clean
5. cd /usr/ports/www/rubygem-mongrel/ && make install clean
Some gems are not available through ports
6a wget http://rubyforge.org/frs/download.php/29624/postgres-0.7.9.2007.12.22.gem
6b /usr/bin/gem18 install --no-ri --install-dir /usr/local/lib/ruby/gems/1.8 ./postgres-0.7.9.2007.12.22.gem (There's a chance that it's not gem18, but gem I'll assume it's the correct path, if not, replace it on the following steps too)
7. /usr/bin/gem18 aws-s3 diff-lcs acts_as_versioned html5 (Accept all dependencies)
5)) Danbooru installation
1. Create the danbooru user, -> adduser (danbooru, and choose a password)
2. cd /home/danbooru
3. svn co svn://danbooru.donmai.us/danbooru/trunk (This will get you the latest trunk)
4. cd trunk/
5. mv * ..
6. cd ..
7. rm -r trunk/
8. Database creation:
8a su pgsql
8b CREATE DATABASE danbooru;
8c \q
8d psql -d danbooru -f /home/danbooru/db/postgres.sql
8e exit
6)) Danbooru configuration
1. cd /home/danbooru/config
2. mv database.yml.example database.yml
3. nano database.yml
3a Change all users to pgsql (Control+X to save and exit)
4. mv local_config.rb.example local_config.rb
5. nano local_config.rb
NOTE: You can check for additional configuration parameters and a brief explanation in default_config.rb
5a. Change the parameters needed an add these parameters
CONFIG["password_salt"] = “choujin-steinerr” (replace the salt with something else)
CONFIG["image_store"] = :local_flat (replace with :local_hierarchy if you want scaled folders for example /01/23/fullhash.ext, leave :local_falt to leave all the images in one same folder)
CONFIG["enable_caching"] = false (change to true to enable memcache, this will speed up things)
CONFIG["memcache_servers"] = ["localhost:4000"] (change to "localhost:11211")
5b Control + X to save and exit.
6. Compiling the resizer
6a You can rather choose between using "ruby extconf.rb" or "ruby extconf.rb --with-gd-dir=/usr/local/gd", if you are using this last option you can ignore the 6b 6c and 6d steps. Using the first method will give you always the same gd version while the second command, the gd version will be updated when you update it through ports.
6b cp /usr/local/include/gd.h gd.h
6c cp /usr/local/include/gd_io.h gd_io.h
6d cp /usr/local/include/gdfx.h gdfx.h
6e make
6f make install
7. cd /home/danbooru
7b /usr/local/bin/rake db:migrate
7)) Basic webserver
- Now you can run "mongrel_rails start", this will make danbooru public on your hostname:3000. You will see debug information in the console
- For running it with mongrel and serving it "normally" you can use "mongrel_rails start -p 80 -d" This will tell mongrel to run on port 80 and as a daemon (not displaying anything in the console)
8)) Advanced webserver
Is encouraged that you rather configure Apache or lighttpd to proxy (or vhosting) the rails app. However this last method requries advanced configuration files and server modules.
If you plan only on running danbooru here's a good configuration for lighttpd usage (you can install it through ports)
Mongrel running as a daemon (4 threads) You might want to add this to the rc.conf if you want to start it automatically
1. cd /home/danbooru
2a mongrel_rails start -d -p 8001 -e production -P log/mongrel-1.pid
2b mongrel_rails start -d -p 8002 -e production -P log/mongrel-2.pid
2c mongrel_rails start -d -p 8003 -e production -P log/mongrel-3.pid
2d mongrel_rails start -d -p 8004 -e production -P log/mongrel-4.pid
Then on lighttpd.conf be sure to have the following mods enabled (Remove # before its names if not):
-mod_rewrite
-mod_redirect
-mod_access
-mod_accesslog
-mod_compress
-mod_proxy
3. Add this to your lighttpd.conf:
proxy.balance = "fair"
proxy.server = ( "/" =>
( ( "host" => "127.0.0.1", "port" => 8001 ),
( "host" => "127.0.0.1", "port" => 8002 ),
( "host" => "127.0.0.1", "port" => 8003 ),
( "host" => "127.0.0.1", "port" => 8004 ) ) )
4. Restart lighttpd: "/usr/local/etc/rc.d/lighttpd restart"

262
README
View File

@@ -1,243 +1,55 @@
== Welcome to Rails === Installation
Rails is a web-application framework that includes everything needed to create It is recommended that you install Danbooru on a Debian-based system (Lenny or newer) since most of the required packages are available on APT. Although Danbooru has been successfully installed on Fedora, CentOS, FreeBSD, and OS X, the following instructions will assume you're installing on Debian. The Debian install script is straightforward and should be simple to adapt for other platforms. Install docs for other platforms are provided, but these are user contributed and may not be up to date. If you want something similar to Danbooru that is easier to install, try Shimmie (http://trac.shishnet.org/shimmie2). Shimmie uses PHP and MySQL and should be straightforward to install on most hosts.
database-backed web applications according to the Model-View-Control pattern.
This pattern splits the view (also called the presentation) into "dumb" templates For best performance, you will need at least 256MB of RAM for PostgreSQL and Rails. The memory requirement will grow as your database gets bigger; the main Danbooru database takes up around 1GB of memory by itself.
that are primarily responsible for inserting pre-built data in between HTML tags.
The model contains the "smart" domain objects (such as Account, Product, Person,
Post) that holds all the business logic and knows how to persist themselves to
a database. The controller handles the incoming requests (such as Save New Account,
Update Product, Show Post) by manipulating the model and directing data to the view.
In Rails, the model is handled by what's called an object-relational mapping - Danbooru has the following general dependencies: gcc, g++, make, readline, zlib, flex, bison, gd2, bzip2, postgresql-8.4, postgresql-contrib-8.4, ruby, rubygems, memcached, subversion, apache, and phusion passenger. Use your operating system's package management system whenever possible. This will simplify the process of installing init scripts, which will not always happen when compiling from source.
layer entitled Active Record. This layer allows you to present the data from - Please read the section below about PostgreSQL and test_parser before proceeding.
database rows as objects and embellish these data objects with business logic - Danbooru has the following Ruby gem dependencies: pg, diff-lcs, html5, memcache-client, aws-s3, json, rails (version 3.0)
methods. You can read more about Active Record in - You may need to specify the path to your PostgreSQL libraries and includes when building the postgres gem. The general format for this is: "gem install postgres -- --with-pgsql-dir=/usr/local/pgsql". Experiment with the other configure settings if this doesn't work.
link:files/vendor/rails/activerecord/README.html. - It's recommended you create a dedicated account for running the Danbooru database and/or web processes. If you go this route:
- Use the createuser command while logged in as postgres to grant database access to the danbooru account.
- You will need to update the pg_hba.conf file to grant your danbooru account trusted localhost access. Make sure to restart the database server (/etc/init.d/postgresql-8.3 restart) after making any changes.
- You now have to check out the Danbooru source code. It's recommended you create it in the /var/www directory, but you can put the code anywhere.
- To export from Subversion: "svn export svn://donmai.us/danbooru/trunk danbooru"
- Recursively change the owner of this directory to the danbooru account: "chown -R danbooru:danbooru danbooru"
- Create a public/data/sample directory.
- Compile the resizer at lib/danbooru_image_resizer: "ruby extconf.rb && make". Do not make install it. If this fails you will need to figure out your gd2/libjpeg/libpng dependencies.
- Create new database.yml and local_config.rb files in the config directory. Example files are provided.
- Create the database: "createdb danbooru"
- Load the schema: "psql danbooru < db/postgres.sql"
- Run the migrations: "RAILS_ENV=production rake db:migrate"
- Start the job daemon: "RAILS_ENV=production app/daemons/job_task_processor_ctl.rb start"
- You now need a way of managing the Rails process. The preferred method is using the Phusion Passenger module (see section below). Alternatively you can use Mongrel or fastcgi, there are several examples on the web.
- You should now be able to connect to your Danbooru instance. The first account you create will automatically become the administrator, so you should do this first.
The controller and view are handled by the Action Pack, which handles both === PostgreSQL and test_parser
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.
Starting with version 1.16, Danbooru relies on PostgreSQL's full text search feature to speed up tag queries. The gains are especially noticeable on tags with large post counts and for multi-tag joins. Unfortunately in order to adapt it for Danbooru a custom parser is required.
== Getting Started The easiest way of doing this on Debian is installing the the postgresql-contrib-8.4 package. You should do this prior to running the Danbooru database migrations.
1. At the command prompt, start a new Rails application using the <tt>rails</tt> command === Apache and Phusion Passenger
and your application name. Ex: rails myapp
2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
3. Go to http://localhost:3000/ and get "Welcome aboard: You're riding the Rails!"
4. Follow the guidelines to start developing your application
Phusion Passenger is essentially mod_rails, a compiled module for Apache that is similar in functionality to fastcgi. It is used instead of fastcgi or Mongrel to proxy requests between Rails processes that Passenger manages. When used in conjunction with Ruby Enterprise Edition you can see improved performance and memory efficiency. Passenger also makes deployments much easier, requiring that you only touch a file called "restart.txt" in your tmp directory.
== Web Servers Installing Passenger on Debian is relatively painless; you can follow the instructions here: http://www.modrails.com/install.html. Passenger will automatically detect Rails folders so the Apache configuration for your site will be basic; the Passenger website explains in detail.
By default, Rails will try to use Mongrel if it's are installed when started with script/server, otherwise Rails will use WEBrick, the webserver that ships with Ruby. But you can also use Rails === Ruby Enterprise Edition
with a variety of other web servers.
Mongrel is a Ruby-based webserver with a C component (which requires compilation) that is REE is a special version of the Ruby interpreter that, among other things, uses a more intelligent malloc routine and performs copy-on-write garbage collection. The end result is better memory usage, up to 30% in ideal cases.
suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
More info at: http://mongrel.rubyforge.org
Say other Ruby web servers like Thin and Ebb or regular web servers like Apache or LiteSpeed or It is fairly straightforward to install and won't override your existing Ruby installation. Find out more here: http://www.rubyenterpriseedition.com
Lighttpd or IIS. The Ruby web servers are run through Rack and the latter can either be setup to use
FCGI or proxy to a pack of Mongrels/Thin/Ebb servers.
== Apache .htaccess example for FCGI/CGI === Troubleshooting
# General Apache options These instructions won't work for everyone. If your setup is not working, here are the steps I usually reccommend to people:
AddHandler fastcgi-script .fcgi
AddHandler cgi-script .cgi
Options +FollowSymLinks +ExecCGI
# If you don't want Rails to look in certain directories, 1) Test the database. Make sure you can connect to it using psql. Make sure the tables exist. If this fails, you need to work on correctly installing PostgreSQL, importing the initial schema, and running the migrations.
# use the following rewrite rules so that Apache won't rewrite certain requests
#
# Example:
# RewriteCond %{REQUEST_URI} ^/notrails.*
# RewriteRule .* - [L]
# Redirect all requests not available on the filesystem to Rails 2) Test the Rails database connection by using ruby script/console. Run Post.count to make sure Rails can connect to the database. If this fails, you need to make sure your Danbooru configuration files are correct.
# By default the cgi dispatcher is used which is very slow
#
# For better performance replace the dispatcher with the fastcgi one
#
# Example:
# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
RewriteEngine On
# If your Rails application is accessed via an Alias directive, 3) If you're using Mongrel, test connecting directly to the Mongrel process by running elinks http://localhost:PORT. If this fails, you need to debug your Mongrel configuration file.
# then you MUST also set the RewriteBase in this htaccess file.
#
# Example:
# Alias /myrailsapp /path/to/myrailsapp/public
# RewriteBase /myrailsapp
RewriteRule ^$ index.html [QSA] 4) Test Apache to make sure it's proxying requests correctly. If this fails, you need to debug your Apache configuration file.
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
# In case Rails experiences terminal errors
# Instead of displaying this message you can supply a file here which will be rendered instead
#
# Example:
# ErrorDocument 500 /500.html
ErrorDocument 500 "<h2>Application error</h2>Rails application failed to start properly"
== Debugging Rails
Sometimes your application goes wrong. Fortunately there are a lot of tools that
will help you debug it and get it back on the rails.
First area to check is the application log files. Have "tail -f" commands running
on the server.log and development.log. Rails will automatically display debugging
and runtime information to these files. Debugging info will also be shown in the
browser on requests from 127.0.0.1.
You can also log your own messages directly into the log file from your code using
the Ruby logger class from inside your controllers. Example:
class WeblogController < ActionController::Base
def destroy
@weblog = Weblog.find(params[:id])
@weblog.destroy
logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
end
end
The result will be a message in your log file along the lines of:
Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1
More information on how to use the logger is at http://www.ruby-doc.org/core/
Also, Ruby documentation can be found at http://www.ruby-lang.org/ including:
* The Learning Ruby (Pickaxe) Book: http://www.ruby-doc.org/docs/ProgrammingRuby/
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
These two online (and free) books will bring you up to speed on the Ruby language
and also on programming in general.
== Debugger
Debugger support is available through the debugger command when you start your Mongrel or
Webrick server with --debugger. This means that you can break out of execution at any point
in the code, investigate and change the model, AND then resume execution!
You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'
Example:
class WeblogController < ActionController::Base
def index
@posts = Post.find(:all)
debugger
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the server window. Here you can do things like:
>> @posts.inspect
=> "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
#<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
>> @posts.first.title = "hello from a debugger"
=> "hello from a debugger"
...and even better is that you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you enter "cont"
== Console
You can interact with the domain model by starting the console through <tt>script/console</tt>.
Here you'll have all parts of the application configured, just like it is when the
application is running. You can inspect domain models, change values, and save to the
database. Starting the script without arguments will launch it in the development environment.
Passing an argument will specify a different environment, like <tt>script/console production</tt>.
To reload your controllers and models after launching the console run <tt>reload!</tt>
== dbconsole
You can go to the command line of your database directly through <tt>script/dbconsole</tt>.
You would be connected to the database with the credentials defined in database.yml.
Starting the script without arguments will connect you to the development database. Passing an
argument will connect you to a different database, like <tt>script/dbconsole production</tt>.
Currently works for mysql, postgresql and sqlite.
== Description of Contents
app
Holds all the code that's specific to this particular application.
app/controllers
Holds controllers that should be named like weblogs_controller.rb for
automated URL mapping. All controllers should descend from ApplicationController
which itself descends from ActionController::Base.
app/models
Holds models that should be named like post.rb.
Most models will descend from ActiveRecord::Base.
app/views
Holds the template files for the view that should be named like
weblogs/index.html.erb for the WeblogsController#index action. All views use eRuby
syntax.
app/views/layouts
Holds the template files for layouts to be used with views. This models the common
header/footer method of wrapping views. In your views, define a layout using the
<tt>layout :default</tt> and create a file named default.html.erb. Inside default.html.erb,
call <% yield %> to render the view using this layout.
app/helpers
Holds view helpers that should be named like weblogs_helper.rb. These are generated
for you automatically when using script/generate for controllers. Helpers can be used to
wrap functionality for your views into methods.
config
Configuration files for the Rails environment, the routing map, the database, and other dependencies.
db
Contains the database schema in schema.rb. db/migrate contains all
the sequence of Migrations for your schema.
doc
This directory is where your application documentation will be stored when generated
using <tt>rake doc:app</tt>
lib
Application specific libraries. Basically, any kind of custom code that doesn't
belong under controllers, models, or helpers. This directory is in the load path.
public
The directory available for the web server. Contains subdirectories for images, stylesheets,
and javascripts. Also contains the dispatchers and the default HTML files. This should be
set as the DOCUMENT_ROOT of your web server.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures. When using the script/generate scripts, template
test files will be generated for you and placed in this directory.
vendor
External libraries that the application depends on. Also includes the plugins subdirectory.
If the app has frozen rails, those gems also go here, under vendor/rails/.
This directory is in the load path.

View File

View File

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

390
app/models/post.rb Normal file
View File

@@ -0,0 +1,390 @@
class Post < ActiveRecord::Base
class Deletion < ActiveRecord::Base
set_table_name "deleted_posts"
end
class Pending < ActiveRecord::Base
set_table_name "pending_posts"
def process!
update_attribute(:status, "processing")
move_file
calculate_hash
calculate_dimensions
generate_resizes
convert_to_post
update_attribute(:status, "finished")
end
def move_file
# Download the file
# Move the tempfile into the data store
# Distribute to other servers
end
def calculate_hash
# Calculate the MD5 hash of the file
end
def calculate_dimensions
# Calculate the dimensions of the image
end
def generate_resizes
# Generate width=150
# Generate width=1000
#
end
def convert_to_post
end
private
def download_from_source
self.source = "" if source.nil?
return if source !~ /^http:\/\// || !file_ext.blank?
begin
Danbooru.http_get_streaming(source) do |response|
File.open(tempfile_path, "wb") do |out|
response.read_body do |block|
out.write(block)
end
end
end
if source.to_s =~ /\/src\/\d{12,}|urnc\.yi\.org|yui\.cynthia\.bne\.jp/
self.source = "Image board"
end
return true
rescue SocketError, URI::Error, SystemCallError => x
delete_tempfile
errors.add "source", "couldn't be opened: #{x}"
return false
end
end
def move_tempfile
end
def distribute_file
end
def generate_resize_for(width)
end
end
class Version < ActiveRecord::Base
set_table_name "post_versions"
end
module FileMethods
def self.included(m)
m.before_validation_on_create :download_source
m.before_validation_on_create :validate_tempfile_exists
m.before_validation_on_create :determine_content_type
m.before_validation_on_create :validate_content_type
m.before_validation_on_create :generate_hash
m.before_validation_on_create :set_image_dimensions
m.before_validation_on_create :generate_sample
m.before_validation_on_create :generate_preview
m.before_validation_on_create :move_file
end
def validate_tempfile_exists
unless File.exists?(tempfile_path)
errors.add :file, "not found, try uploading again"
return false
end
end
def validate_content_type
unless %w(jpg png gif swf).include?(file_ext.downcase)
errors.add(:file, "is an invalid content type: " + file_ext.downcase)
return false
end
end
def file_name
md5 + "." + file_ext
end
def delete_tempfile
FileUtils.rm_f(tempfile_path)
FileUtils.rm_f(tempfile_preview_path)
FileUtils.rm_f(tempfile_sample_path)
end
def tempfile_path
"#{RAILS_ROOT}/public/data/#{$PROCESS_ID}.upload"
end
def tempfile_preview_path
"#{RAILS_ROOT}/public/data/#{$PROCESS_ID}-preview.jpg"
end
# def file_size
# File.size(file_path) rescue 0
# end
# Generate an MD5 hash for the file.
def generate_hash
unless File.exists?(tempfile_path)
errors.add(:file, "not found")
return false
end
self.md5 = File.open(tempfile_path, 'rb') {|fp| Digest::MD5.hexdigest(fp.read)}
self.file_size = File.size(tempfile_path)
if Post.exists?(["md5 = ?", md5])
delete_tempfile
errors.add "md5", "already exists"
return false
else
return true
end
end
def generate_preview
return true unless image? && width && height
unless File.exists?(tempfile_path)
errors.add(:file, "not found")
return false
end
size = Danbooru.reduce_to({:width=>width, :height=>height}, {:width=>150, :height=>150})
# Generate the preview from the new sample if we have one to save CPU, otherwise from the image.
if File.exists?(tempfile_sample_path)
path, ext = tempfile_sample_path, "jpg"
else
path, ext = tempfile_path, file_ext
end
begin
Danbooru.resize(ext, path, tempfile_preview_path, size, 95)
rescue Exception => x
errors.add "preview", "couldn't be generated (#{x})"
return false
end
return true
end
# Automatically download from the source if it's a URL.
def download_source
self.source = "" if source.nil?
return if source !~ /^http:\/\// || !file_ext.blank?
begin
Danbooru.http_get_streaming(source) do |response|
File.open(tempfile_path, "wb") do |out|
response.read_body do |block|
out.write(block)
end
end
end
if source.to_s =~ /\/src\/\d{12,}|urnc\.yi\.org|yui\.cynthia\.bne\.jp/
self.source = "Image board"
end
return true
rescue SocketError, URI::Error, SystemCallError => x
delete_tempfile
errors.add "source", "couldn't be opened: #{x}"
return false
end
end
def determine_content_type
imgsize = ImageSize.new(File.open(tempfile_path, "rb"))
unless imgsize.get_width.nil?
self.file_ext = imgsize.get_type.gsub(/JPEG/, "JPG").downcase
end
end
# Assigns a CGI file to the post. This writes the file to disk and generates a unique file name.
def file=(f)
return if f.nil? || f.size == 0
self.file_ext = content_type_to_file_ext(f.content_type) || find_ext(f.original_filename)
if f.local_path
# Large files are stored in the temp directory, so instead of
# reading/rewriting through Ruby, just rely on system calls to
# copy the file to danbooru's directory.
FileUtils.cp(f.local_path, tempfile_path)
else
File.open(tempfile_path, 'wb') {|nf| nf.write(f.read)}
end
end
def set_image_dimensions
if image? or flash?
imgsize = ImageSize.new(File.open(tempfile_path, "rb"))
self.width = imgsize.get_width
self.height = imgsize.get_height
end
end
# Returns true if the post is an image format that GD can handle.
def image?
%w(jpg jpeg gif png).include?(file_ext.downcase)
end
# Returns true if the post is a Flash movie.
def flash?
file_ext == "swf"
end
def find_ext(file_path)
ext = File.extname(file_path)
if ext.blank?
return "txt"
else
ext = ext[1..-1].downcase
ext = "jpg" if ext == "jpeg"
return ext
end
end
def content_type_to_file_ext(content_type)
case content_type.chomp
when "image/jpeg"
return "jpg"
when "image/gif"
return "gif"
when "image/png"
return "png"
when "application/x-shockwave-flash"
return "swf"
else
nil
end
end
def preview_dimensions
if image?
dim = Danbooru.reduce_to({:width => width, :height => height}, {:width => 150, :height => 150})
return [dim[:width], dim[:height]]
else
return [150, 150]
end
end
def tempfile_sample_path
"#{RAILS_ROOT}/public/data/#{$PROCESS_ID}-sample.jpg"
end
def regenerate_sample
return false unless image?
if generate_sample && File.exists?(tempfile_sample_path)
FileUtils.mkdir_p(File.dirname(sample_path), :mode => 0775)
FileUtils.mv(tempfile_sample_path, sample_path)
FileUtils.chmod(0775, sample_path)
puts "Fixed sample for #{id}"
return true
else
puts "Error generating sample for #{id}"
return false
end
end
def generate_sample
return true unless image?
return true unless CONFIG["image_samples"]
return true unless (width && height)
return true if (file_ext.downcase == "gif")
size = Danbooru.reduce_to({:width => width, :height => height}, {:width => CONFIG["sample_width"], :height => CONFIG["sample_height"]}, CONFIG["sample_ratio"])
# We can generate the sample image during upload or offline. Use tempfile_path
# if it exists, otherwise use file_path.
path = tempfile_path
path = file_path unless File.exists?(path)
unless File.exists?(path)
errors.add(:file, "not found")
return false
end
# If we're not reducing the resolution for the sample image, only reencode if the
# source image is above the reencode threshold. Anything smaller won't be reduced
# enough by the reencode to bother, so don't reencode it and save disk space.
if size[:width] == width && size[:height] == height && File.size?(path) < CONFIG["sample_always_generate_size"]
return true
end
# If we already have a sample image, and the parameters havn't changed,
# don't regenerate it.
if size[:width] == sample_width && size[:height] == sample_height
return true
end
size = Danbooru.reduce_to({:width => width, :height => height}, {:width => CONFIG["sample_width"], :height => CONFIG["sample_height"]})
begin
Danbooru.resize(file_ext, path, tempfile_sample_path, size, 90)
rescue Exception => x
errors.add "sample", "couldn't be created: #{x}"
return false
end
self.sample_width = size[:width]
self.sample_height = size[:height]
return true
end
# Returns true if the post has a sample image.
def has_sample?
sample_width.is_a?(Integer)
end
# Returns true if the post has a sample image, and we're going to use it.
def use_sample?(user = nil)
if user && !user.show_samples?
false
else
CONFIG["image_samples"] && has_sample?
end
end
def sample_url(user = nil)
if use_sample?(user)
store_sample_url
else
file_url
end
end
def get_sample_width(user = nil)
if use_sample?(user)
sample_width
else
width
end
end
def get_sample_height(user = nil)
if use_sample?(user)
sample_height
else
height
end
end
def sample_percentage
100 * get_sample_width.to_f / width
end
end
end

2
app/models/tag.rb Normal file
View File

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

47
app/models/user.rb Normal file
View File

@@ -0,0 +1,47 @@
require 'digest/sha1'
class User < ActiveRecord::Base
attr_accessor :password
validates_length_of :name, :within => 2..20, :on => :create
validates_format_of :name, :with => /\A[^\s;,]+\Z/, :on => :create, :message => "cannot have whitespace, commas, or semicolons"
validates_uniqueness_of :name, :case_sensitive => false, :on => :create
validates_uniqueness_of :email, :case_sensitive => false, :on => :create, :if => lambda {|rec| !rec.email.blank?}
validates_confirmation_of :password
before_save :encrypt_password
after_save {|rec| Cache.put("user_name:#{rec.id}", rec.name)}
scope :named, lambda {|name| where(["lower(name) = ?", name])}
def self.authenticate(name, pass)
authenticate_hash(name, sha1(pass))
end
def self.authenticate_hash(name, pass)
where(["lower(name) = ? AND password_hash = ?", name.downcase, pass]).first != nil
end
def self.sha1(pass)
Digest::SHA1.hexdigest("#{Danbooru.config.password_salt}--#{pass}--")
end
def self.find_name(user_id)
Cache.get("user_name:#{user_id}") do
select_value_sql("SELECT name FROM users WHERE id = ?", user_id) || Danbooru.config.default_guest_name
end
end
def can_update?(object, foreign_key = :user_id)
is_moderator? || is_admin? || object.__send__(foreign_key) == id
end
def pretty_name
name.tr("_", " ")
end
def encrypt_password
self.password_hash = self.class.sha1(password) if password
end
end

View File

@@ -0,0 +1,41 @@
=begin rdoc
A tag set represents a set of tags that are displayed together.
This class makes it easy to fetch the categories for all the
tags in one call instead of fetching them sequentially.
=end
class TagSetPresenter < Presenter
def initialize(source)
@category_cache = {}
end
def to_list_html(template, options = {})
ul_class_attribute = options[:ul_class] ? %{class="#{options[:ul_class]}"} : ""
ul_id_attribute = options[:ul_id] ? %{id="#{options[:ul_id]}"} : ""
html = ""
html << "<ul #{ul_class_attribute} #{ul_id_attribute}>"
@tags.each do |tag|
html << build_list_item(tag, template, options)
end
html << "</ul>"
html
end
private
def fetch_categories(tags)
end
def build_list_item(tag, template, options)
html = ""
html << "<li>"
if options[:show_extra_links]
end
humanized_tag = tag.tr("_", " ")
html << %{a href="/posts?tags=#{u(tag)}">#{h(humanized_tag)}</a>}
html << "</li>"
html
end
end

View File

@@ -1,4 +1,4 @@
# This file is used by Rack-based servers to start the application. # This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__) require ::File.expand_path('../config/environment', __FILE__)
run Danbooru2::Application run Danbooru::Application

View File

@@ -5,26 +5,15 @@ require 'rails/all'
# Auto-require default libraries and those for the current Rails environment. # Auto-require default libraries and those for the current Rails environment.
Bundler.require :default, Rails.env Bundler.require :default, Rails.env
module Danbooru2 module Danbooru
class Application < Rails::Application class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Add additional load paths for your own custom dirs # Add additional load paths for your own custom dirs
# config.load_paths += %W( #{config.root}/extras ) config.load_paths += %W( #{config.root}/presenters #{config.root}/logical )
# Only load the plugins named here, in the order given (default is alphabetical). # Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named # :all can be used as a placeholder for all plugins not explicitly named
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
# config.i18n.default_locale = :de # config.i18n.default_locale = :de
@@ -36,6 +25,8 @@ module Danbooru2
# g.test_framework :test_unit, :fixture => true # g.test_framework :test_unit, :fixture => true
# end # end
config.active_record.schema_format = :sql
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters << :password config.filter_parameters << :password
end end

View File

@@ -0,0 +1,109 @@
module Danbooru
class Configuration
# The version of this Danbooru.
def version
"2.0.0"
end
# The name of this Danbooru.
def app_name
"Danbooru"
end
# The default name to use for anyone who isn't logged in.
def default_guest_name
"Anonymous"
end
# This is a salt used to make dictionary attacks on account passwords harder.
def password_salt
"choujin-steiner"
end
# Set to true to allow new account signups.
def enable_signups?
true
end
# Set to true to give all new users privileged access.
def start_as_privileged?
false
end
# Set to true to give all new users contributor access.
def start_as_contributor?
false
end
# What method to use to store images.
# local_flat: Store every image in one directory.
# local_hierarchy: Store every image in a hierarchical directory, based on the post's MD5 hash. On some file systems this may be faster.
def image_store
:local_flat
end
# Thumbnail size
def small_image_width
150
end
# Medium resize image width
def medium_image_width
500
end
# Large resize image width
def large_image_width
1024
end
# List of memcached servers
def memcached_servers
%w(localhost:11211)
end
# After a post receives this many comments, new comments will no longer bump the post in comment/index.
def comment_threshold
40
end
# Members cannot post more than X comments in an hour.
def member_comment_limit
2
end
# Determine who can see a post.
def can_see_post?(post, user)
true
end
# Determines who can see ads.
def can_see_ads?(user)
false
end
# This is required for Rails 2.0.
def session_secret_key
"This should be at least 30 characters long"
end
# Users cannot search for more than X regular tags at a time.
def tag_query_limit
6
end
# Max number of posts to cache
def tag_subscription_post_limit
200
end
# Max number of tag subscriptions per user
def max_tag_subscriptions
5
end
def server_host
Socket.gethostname
end
end
end

View File

@@ -0,0 +1,5 @@
module Danbooru
class CustomConfiguration < Configuration
# Define your custom overloads here
end
end

View File

@@ -1,8 +1,8 @@
# SQLite version 3.x # SQLite version 3.x
# gem install sqlite3-ruby (not necessary on OS X Leopard) # gem install sqlite3-ruby (not necessary on OS X Leopard)
development: development:
adapter: sqlite3 adapter: postgresql
database: db/development.sqlite3 database: danbooru2
pool: 5 pool: 5
timeout: 5000 timeout: 5000
@@ -10,13 +10,13 @@ development:
# re-generated from your development database when you run "rake". # re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production. # Do not set this db to the same as development or production.
test: test:
adapter: sqlite3 adapter: postgresql
database: db/test.sqlite3 database: danbooru2_test
pool: 5 pool: 5
timeout: 5000 timeout: 5000
production: production:
adapter: sqlite3 adapter: postgresql
database: db/production.sqlite3 database: danbooru2
pool: 5 pool: 5
timeout: 5000 timeout: 5000

View File

@@ -2,4 +2,4 @@
require File.expand_path('../application', __FILE__) require File.expand_path('../application', __FILE__)
# Initialize the rails application # Initialize the rails application
Danbooru2::Application.initialize! Danbooru::Application.initialize!

View File

@@ -1,4 +1,4 @@
Danbooru2::Application.configure do Danbooru::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb # Settings specified here will take precedence over those in config/environment.rb
# In the development environment your application's code is reloaded on # In the development environment your application's code is reloaded on

View File

@@ -1,4 +1,4 @@
Danbooru2::Application.configure do Danboorus::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb # Settings specified here will take precedence over those in config/environment.rb
# The production environment is meant for finished, "live" apps. # The production environment is meant for finished, "live" apps.

View File

@@ -1,4 +1,4 @@
Danbooru2::Application.configure do Danbooru::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb # Settings specified here will take precedence over those in config/environment.rb
# The test environment is used exclusively to run your application's # The test environment is used exclusively to run your application's

View File

@@ -4,4 +4,4 @@
# If you change this key, all old signed cookies will become invalid! # If you change this key, all old signed cookies will become invalid!
# Make sure the secret is at least 30 characters and all random, # Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks. # no regular words or you'll be exposed to dictionary attacks.
ActionController::Base.cookie_verifier_secret = '9d3404d788351e80007345ca60b0cc4484e1906a2feab4be105e0637946c220e1f7239902b4234892923b9b45cf6f9a0a818302d81f890849e9bfe19ce03a30d' ActionController::Base.cookie_verifier_secret = '214c98302eef905ab8bce4a19562e322097c526f28e718160a3c0d617ddc8edab6ae7e22cb5eec8930e215bfb936a7086d6f5b146c0092a9af1884613ce0a260'

View File

@@ -0,0 +1,31 @@
class ActiveRecord::Base
class << self
public :sanitize_sql_array
end
%w(execute select_value select_values select_all).each do |method_name|
define_method("#{method_name}_sql") do |sql, *params|
connection.__send__(method_name, self.class.sanitize_sql_array([sql, *params]))
end
self.class.__send__(:define_method, "#{method_name}_sql") do |sql, *params|
connection.__send__(method_name, sanitize_sql_array([sql, *params]))
end
end
end
class NilClass
def id
raise NoMethodError
end
end
class String
def to_escaped_for_sql_like
return self.gsub(/\\/, '\0\0').gsub(/%/, '\\%').gsub(/_/, '\\_').gsub(/\*/, '%')
end
def to_escaped_js
return self.gsub(/\\/, '\0\0').gsub(/['"]/) {|m| "\\#{m}"}.gsub(/\r\n|\r|\n/, '\\n')
end
end

View File

@@ -0,0 +1,10 @@
require "#{Rails.root}/config/danbooru_default_config"
require "#{Rails.root}/config/danbooru_local_config"
module Danbooru
def config
@configuration ||= CustomConfiguration.new
end
module_function :config
end

View File

@@ -0,0 +1,6 @@
require 'memcache'
unless defined?(MEMCACHE)
MEMCACHE = MemCache.new :c_threshold => 10_000, :compression => true, :debug => false, :namespace => Danbooru.config.app_name.gsub(/[^A-Za-z0-9]/, "_"), :readonly => false, :urlencode => false
MEMCACHE.servers = Danbooru.config.memcached_servers
end

View File

@@ -5,8 +5,8 @@
# Make sure the secret is at least 30 characters and all random, # Make sure the secret is at least 30 characters and all random,
# no regular words or you'll be exposed to dictionary attacks. # no regular words or you'll be exposed to dictionary attacks.
ActionController::Base.session = { ActionController::Base.session = {
:key => '_danbooru2_session', :key => '_danbooru_session',
:secret => '8c46b9a05b0222b74454c6f4bd461be89cc762d9ef3dab4513997670ffed45086bc7a025d45ead5accca656cfb9ab64e70dd44c4379653cf8d4ca45f455ac8ec' :secret => '3102c705148af8124298f9e89d45da3d26e47cc4d9a67cb1c8d9c42c008ee253786346efda50331bb14811f1f445c1c9ed2d51597ad2017328de0dd263048d1a'
} }
# Use the database for sessions instead of the cookie-based default, # Use the database for sessions instead of the cookie-based default,

View File

@@ -1,4 +1,4 @@
Danbooru2::Application.routes.draw do |map| Danbooru::Application.routes.draw do |map|
# The priority is based upon order of creation: # The priority is based upon order of creation:
# first created -> highest priority. # first created -> highest priority.

View File

@@ -0,0 +1,115 @@
--
-- PostgreSQL database dump
--
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
--
-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
CREATE TABLE schema_migrations (
version character varying(255) NOT NULL
);
--
-- Name: users; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
CREATE TABLE users (
id integer NOT NULL,
created_at timestamp without time zone,
updated_at timestamp without time zone,
name character varying(255) NOT NULL,
password_hash character varying(255) NOT NULL,
email character varying(255),
invited_by integer,
is_banned boolean DEFAULT false NOT NULL,
is_privileged boolean DEFAULT false NOT NULL,
is_contributor boolean DEFAULT false NOT NULL,
is_janitor boolean DEFAULT false NOT NULL,
is_moderator boolean DEFAULT false NOT NULL,
is_admin boolean DEFAULT false NOT NULL,
last_logged_in_at timestamp without time zone,
last_forum_read_at timestamp without time zone,
has_mail boolean DEFAULT false NOT NULL,
receive_email_notifications boolean DEFAULT false NOT NULL,
comment_threshold integer DEFAULT (-1) NOT NULL,
always_resize_images boolean DEFAULT false NOT NULL,
favorite_tags text,
blacklisted_tags text
);
--
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE users_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
--
-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE users_id_seq OWNED BY users.id;
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE users ALTER COLUMN id SET DEFAULT nextval('users_id_seq'::regclass);
--
-- Name: users_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
--
ALTER TABLE ONLY users
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
--
-- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE UNIQUE INDEX index_users_on_email ON users USING btree (email);
--
-- Name: index_users_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE UNIQUE INDEX index_users_on_name ON users USING btree (lower((name)::text));
--
-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE UNIQUE INDEX unique_schema_migrations ON schema_migrations USING btree (version);
--
-- PostgreSQL database dump complete
--
INSERT INTO schema_migrations (version) VALUES ('20100204211522');

View File

@@ -0,0 +1,37 @@
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.timestamps
t.column :name, :string, :null => false
t.column :password_hash, :string, :null => false
t.column :email, :string
t.column :invited_by, :integer
t.column :is_banned, :boolean, :null => false, :default => false
t.column :is_privileged, :boolean, :null => false, :default => false
t.column :is_contributor, :boolean, :null => false, :default => false
t.column :is_janitor, :boolean, :null => false, :default => false
t.column :is_moderator, :boolean, :null => false, :default => false
t.column :is_admin, :boolean, :null => false, :default => false
# Cached data
t.column :last_logged_in_at, :datetime
t.column :last_forum_read_at, :datetime
t.column :has_mail, :boolean, :null => false, :default => false
# Profile settings
t.column :receive_email_notifications, :boolean, :null => false, :default => false
t.column :comment_threshold, :integer, :null => false, :default => -1
t.column :always_resize_images, :boolean, :null => false, :default => false
t.column :favorite_tags, :text
t.column :blacklisted_tags, :text
end
execute "CREATE UNIQUE INDEX index_users_on_name ON users ((lower(name)))"
add_index :users, :email, :unique => true
end
def self.down
drop_table :users
end
end

92
lib/cache.rb Normal file
View File

@@ -0,0 +1,92 @@
module Cache
def expire(options = {})
tags = options[:tags]
cache_version = Cache.get("$cache_version").to_i
Cache.put("$cache_version", cache_version + 1)
if tags
tags.scan(/\S+/).each do |x|
key = "tag:#{x}"
key_version = Cache.get(key).to_i
Cache.put(key, key_version + 1)
end
end
end
def incr(key)
val = Cache.get(key)
Cache.put(key, val.to_i + 1)
ActiveRecord::Base.logger.debug('MemCache Incr %s' % [key])
end
def get(key, expiry = 0)
key.gsub!(/\s/, "_")
key = key[0, 200]
if block_given?
return yield
else
return nil
end
begin
start_time = Time.now
value = MEMCACHE.get key
elapsed = Time.now - start_time
ActiveRecord::Base.logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
if value.nil? and block_given? then
value = yield
MEMCACHE.set key, value, expiry
end
value
rescue MemCache::MemCacheError => err
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
if block_given? then
value = yield
put key, value, expiry
end
value
end
end
def put(key, value, expiry = 0)
key.gsub!(/\s/, "_")
key = key[0, 200]
begin
start_time = Time.now
MEMCACHE.set key, value, expiry
elapsed = Time.now - start_time
ActiveRecord::Base.logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
value
rescue MemCache::MemCacheError => err
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
nil
end
end
def delete(key, delay = nil)
begin
start_time = Time.now
MEMCACHE.delete key, delay
elapsed = Time.now - start_time
ActiveRecord::Base.logger.debug('MemCache Delete (%0.6f) %s' % [elapsed, key])
nil
rescue MemCache::MemCacheError => err
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
nil
end
end
def sanitize_key(key)
key.gsub(/\W/, "_").slice(0, 220)
end
module_function :get
module_function :expire
module_function :incr
module_function :put
module_function :delete
module_function :sanitize_key
end

View File

@@ -1,4 +1,11 @@
document.observe("dom:loaded", function() { document.observe("dom:loaded", function() {
var authToken = $$('meta[name=csrf-token]').first().readAttribute('content'),
authParam = $$('meta[name=csrf-param]').first().readAttribute('content'),
formTemplate = '<form method="#{method}" action="#{action}">\
#{realmethod}<input name="#{param}" value="#{token}" type="hidden">\
</form>',
realmethodTemplate = '<input name="_method" value="#{method}" type="hidden">';
function handleRemote(element) { function handleRemote(element) {
var method, url, params; var method, url, params;
@@ -34,20 +41,46 @@ document.observe("dom:loaded", function() {
} }
$(document.body).observe("click", function(event) { $(document.body).observe("click", function(event) {
var message = event.element().readAttribute('data-confirm');
if (message && !confirm(message)) {
event.stop();
return false;
}
var element = event.findElement("a[data-remote=true]"); var element = event.findElement("a[data-remote=true]");
if (element) { if (element) {
handleRemote(element); handleRemote(element);
event.stop(); event.stop();
} }
});
$(document.body).observe("ajax:before", function(event) { var element = event.findElement("a[data-method]");
var message = event.element().readAttribute('data-confirm'); if (element && element.readAttribute('data-remote') != 'true') {
if (message && !confirm(message)) event.stop(); var method = element.readAttribute('data-method'),
piggyback = method.toLowerCase() != 'post',
formHTML = formTemplate.interpolate({
method: 'POST',
realmethod: piggyback ? realmethodTemplate.interpolate({ method: method }) : '',
action: element.readAttribute('href'),
token: authToken,
param: authParam
});
var form = new Element('div').update(formHTML).down().hide();
this.insert({ bottom: form });
form.submit();
event.stop();
}
}); });
// TODO: I don't think submit bubbles in IE // TODO: I don't think submit bubbles in IE
$(document.body).observe("submit", function(event) { $(document.body).observe("submit", function(event) {
var message = event.element().readAttribute('data-confirm');
if (message && !confirm(message)) {
event.stop();
return false;
}
var inputs = event.element().select("input[type=submit][data-disable-with]"); var inputs = event.element().select("input[type=submit][data-disable-with]");
inputs.each(function(input) { inputs.each(function(input) {
input.disabled = true; input.disabled = true;

29
test/factories/user.rb Normal file
View File

@@ -0,0 +1,29 @@
Factory.define(:user) do |f|
f.name {Faker::Name.first_name}
f.password_hash {User.sha1("password")}
f.email {Faker::Internet.email}
end
Factory.define(:banned_user) do |f|
f.is_banned true
end
Factory.define(:privileged_user) do |f|
f.is_privileged true
end
Factory.define(:contributor_user) do |f|
f.is_contributor true
end
Factory.define(:janitor_user) do |f|
f.is_janitor true
end
Factory.define(:moderator_user) do |f|
f.is_moderator true
end
Factory.define(:admin_user) do |f|
f.is_admin true
end

View File

@@ -1,13 +1,12 @@
ENV["RAILS_ENV"] = "test" ENV["RAILS_ENV"] = "test"
require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'shoulda'
require 'factory_girl'
require 'mocha'
require 'faker'
require 'rails/test_help' require 'rails/test_help'
class ActiveSupport::TestCase Dir[File.expand_path(File.dirname(__FILE__) + "/factories/*.rb")].each {|file| require file}
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here... class ActiveSupport::TestCase
end end

View File

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

View File

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

8
test/unit/post_test.rb Normal file
View File

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

View File

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

8
test/unit/tag_test.rb Normal file
View File

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

17
test/unit/user_test.rb Normal file
View File

@@ -0,0 +1,17 @@
require File.dirname(__FILE__) + '/../test_helper'
class UserTest < ActiveSupport::TestCase
context "A user" do
setup do
MEMCACHE.flush_all
end
should "be authenticate" do
@user = Factory.create(:user)
assert(User.authenticate(@user.name, "password"), "Authentication should have succeeded")
assert(!User.authenticate(@user.name, "password2"), "Authentication should not have succeeded")
assert(User.authenticate_hash(@user.name, @user.password_hash), "Authentication should have succeeded")
assert(!User.authenticate_hash(@user.name, "xxxx"), "Authentication should not have succeeded")
end
end
end

BIN
vendor/cache/abstract-1.0.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/arel-0.2.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/aws-s3-0.6.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/builder-2.1.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/bundler-0.9.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/chardet-0.9.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/diff-lcs-1.1.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/erubis-2.6.5.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/gemcutter-0.3.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/hoe-2.5.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/html5-0.10.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/i18n-0.3.3.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/json-1.2.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/json_pure-1.2.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/mail-2.1.2.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/mechanize-0.9.3.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/memcache-client-1.7.8.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/mime-types-1.16.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/nokogiri-1.4.1.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/pg-0.8.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/rack-1.1.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/rack-mount-0.4.5.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/rack-test-0.5.3.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/rake-0.8.7.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/rubyforge-2.0.3.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/text-format-1.0.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/text-hyphen-1.0.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/thor-0.13.0.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/tzinfo-0.3.16.gem vendored Normal file

Binary file not shown.

BIN
vendor/cache/xml-simple-1.0.12.gem vendored Normal file

Binary file not shown.