Commit 4226458fafc0cd64422c77691a2c802d2347ea2d

Authored by miks
2 parents 909c8c34 7cc4b3f6

Merge branch 'master' into project_users_api

Showing 927 changed files with 1017 additions and 799 deletions   Show diff stats
@@ -22,4 +22,4 @@ config/unicorn.rb @@ -22,4 +22,4 @@ config/unicorn.rb
22 db/data.yml 22 db/data.yml
23 .idea 23 .idea
24 .DS_Store 24 .DS_Store
25 - 25 +.chef
@@ -9,6 +9,8 @@ branches: @@ -9,6 +9,8 @@ branches:
9 - 'master' 9 - 'master'
10 rvm: 10 rvm:
11 - 1.9.3 11 - 1.9.3
  12 +services:
  13 + - mysql
12 before_script: 14 before_script:
13 - "cp config/database.yml.$DB config/database.yml" 15 - "cp config/database.yml.$DB config/database.yml"
14 - "cp config/gitlab.yml.example config/gitlab.yml" 16 - "cp config/gitlab.yml.example config/gitlab.yml"
@@ -108,7 +108,7 @@ GEM @@ -108,7 +108,7 @@ GEM
108 bcrypt-ruby (3.0.1) 108 bcrypt-ruby (3.0.1)
109 blankslate (2.1.2.4) 109 blankslate (2.1.2.4)
110 bootstrap-sass (2.0.4.0) 110 bootstrap-sass (2.0.4.0)
111 - builder (3.0.0) 111 + builder (3.0.2)
112 capybara (1.1.2) 112 capybara (1.1.2)
113 mime-types (>= 1.16) 113 mime-types (>= 1.16)
114 nokogiri (>= 1.3.3) 114 nokogiri (>= 1.3.3)
@@ -125,7 +125,7 @@ GEM @@ -125,7 +125,7 @@ GEM
125 charlock_holmes (0.6.8) 125 charlock_holmes (0.6.8)
126 childprocess (0.3.2) 126 childprocess (0.3.2)
127 ffi (~> 1.0.6) 127 ffi (~> 1.0.6)
128 - chosen-rails (0.9.8) 128 + chosen-rails (0.9.8.3)
129 railties (~> 3.0) 129 railties (~> 3.0)
130 thor (~> 0.14) 130 thor (~> 0.14)
131 coderay (1.0.6) 131 coderay (1.0.6)
app/assets/images/emoji/+1.png 0 → 100755

5.01 KB

app/assets/images/emoji/-1.png 0 → 100755

4.95 KB

app/assets/images/emoji/100.png 0 → 100755

3.22 KB

app/assets/images/emoji/109.png 0 → 100755

3.61 KB

app/assets/images/emoji/1234.png 0 → 100755

4.64 KB

app/assets/images/emoji/8ball.png 0 → 100755

4.04 KB

app/assets/images/emoji/a.png 0 → 100755

3.08 KB

app/assets/images/emoji/ab.png 0 → 100755

3.77 KB

app/assets/images/emoji/abc.png 0 → 100755

4.15 KB

app/assets/images/emoji/abcd.png 0 → 100755

4.37 KB

app/assets/images/emoji/accept.png 0 → 100755

4.62 KB

app/assets/images/emoji/aerial_tramway.png 0 → 100755

3.41 KB

app/assets/images/emoji/airplane.png 0 → 100755

4.63 KB

app/assets/images/emoji/alarm_clock.png 0 → 100755

6.9 KB

app/assets/images/emoji/alien.png 0 → 100755

5.33 KB

app/assets/images/emoji/ambulance.png 0 → 100755

3.62 KB

app/assets/images/emoji/anchor.png 0 → 100755

4.37 KB

app/assets/images/emoji/angel.png 0 → 100755

6.52 KB

app/assets/images/emoji/anger.png 0 → 100755

3.01 KB

app/assets/images/emoji/angry.png 0 → 100755

4.92 KB

app/assets/images/emoji/ant.png 0 → 100755

2.78 KB

app/assets/images/emoji/apple.png 0 → 100755

5.5 KB

app/assets/images/emoji/aquarius.png 0 → 100755

4.98 KB

app/assets/images/emoji/aries.png 0 → 100755

4.24 KB

app/assets/images/emoji/arrow_backward.png 0 → 100755

3.11 KB

app/assets/images/emoji/arrow_double_down.png 0 → 100755

3.1 KB

app/assets/images/emoji/arrow_double_up.png 0 → 100755

3.53 KB

app/assets/images/emoji/arrow_down.png 0 → 100755

2.94 KB

app/assets/images/emoji/arrow_down_small.png 0 → 100755

2.87 KB

app/assets/images/emoji/arrow_forward.png 0 → 100755

3.13 KB

app/assets/images/emoji/arrow_heading_down.png 0 → 100755

3.44 KB

app/assets/images/emoji/arrow_heading_up.png 0 → 100755

3.44 KB

app/assets/images/emoji/arrow_left.png 0 → 100755

2.97 KB

app/assets/images/emoji/arrow_lower_left.png 0 → 100755

3.26 KB

app/assets/images/emoji/arrow_lower_right.png 0 → 100755

3.26 KB

app/assets/images/emoji/arrow_right.png 0 → 100755

2.95 KB

app/assets/images/emoji/arrow_right_hook.png 0 → 100755

3.63 KB

app/assets/images/emoji/arrow_up.png 0 → 100755

3 KB

app/assets/images/emoji/arrow_up_down.png 0 → 100755

3.46 KB

app/assets/images/emoji/arrow_up_small.png 0 → 100755

3.12 KB

app/assets/images/emoji/arrow_upper_left.png 0 → 100755

3.15 KB

app/assets/images/emoji/arrow_upper_right.png 0 → 100755

3.16 KB

app/assets/images/emoji/arrows_clockwise.png 0 → 100755

1.37 KB

app/assets/images/emoji/arrows_counterclockwise.png 0 → 100755

4.71 KB

app/assets/images/emoji/art.png 0 → 100755

6.59 KB

app/assets/images/emoji/articulated_lorry.png 0 → 100755

2.87 KB

app/assets/images/emoji/astonished.png 0 → 100755

5.9 KB

app/assets/images/emoji/atm.png 0 → 100755

3.98 KB

app/assets/images/emoji/b.png 0 → 100755

2.95 KB

app/assets/images/emoji/baby.png 0 → 100755

5.78 KB

app/assets/images/emoji/baby_bottle.png 0 → 100755

4.36 KB

app/assets/images/emoji/baby_chick.png 0 → 100755

3.87 KB

app/assets/images/emoji/baby_symbol.png 0 → 100755

2.9 KB

app/assets/images/emoji/baggage_claim.png 0 → 100755

3.42 KB

app/assets/images/emoji/balloon.png 0 → 100755

2.25 KB

app/assets/images/emoji/ballot_box_with_check.png 0 → 100755

1.79 KB

app/assets/images/emoji/bamboo.png 0 → 100755

4.56 KB

app/assets/images/emoji/banana.png 0 → 100755

3.82 KB

app/assets/images/emoji/bangbang.png 0 → 100755

1.35 KB

app/assets/images/emoji/bank.png 0 → 100755

5.45 KB

app/assets/images/emoji/bar_chart.png 0 → 100755

2.4 KB

app/assets/images/emoji/barber.png 0 → 100755

4.15 KB

app/assets/images/emoji/baseball.png 0 → 100755

5.89 KB

app/assets/images/emoji/basketball.png 0 → 100755

6.24 KB

app/assets/images/emoji/bath.png 0 → 100755

3.13 KB

app/assets/images/emoji/bathtub.png 0 → 100755

2.72 KB

app/assets/images/emoji/battery.png 0 → 100755

3.72 KB

app/assets/images/emoji/bear.png 0 → 100755

5.43 KB

app/assets/images/emoji/beer.png 0 → 100755

5.95 KB

app/assets/images/emoji/beers.png 0 → 100755

6.44 KB

app/assets/images/emoji/beetle.png 0 → 100755

5.13 KB

app/assets/images/emoji/beginner.png 0 → 100755

2.7 KB

app/assets/images/emoji/bell.png 0 → 100755

4.75 KB

app/assets/images/emoji/bento.png 0 → 100755

5.6 KB

app/assets/images/emoji/bicyclist.png 0 → 100755

6.33 KB

app/assets/images/emoji/bike.png 0 → 100755

4.61 KB

app/assets/images/emoji/bikini.png 0 → 100755

3.8 KB

app/assets/images/emoji/bird.png 0 → 100755

4.76 KB

app/assets/images/emoji/birthday.png 0 → 100755

5.28 KB

app/assets/images/emoji/black_circle.png 0 → 100755

2.31 KB

app/assets/images/emoji/black_joker.png 0 → 100755

3.79 KB

app/assets/images/emoji/black_nib.png 0 → 100755

2.3 KB

app/assets/images/emoji/black_square.png 0 → 100755

1.3 KB

app/assets/images/emoji/blossom.png 0 → 100755

4.13 KB

app/assets/images/emoji/blowfish.png 0 → 100755

3.66 KB

app/assets/images/emoji/blue_book.png 0 → 100755

4.97 KB

app/assets/images/emoji/blue_car.png 0 → 100755

3.99 KB

app/assets/images/emoji/blue_heart.png 0 → 100755

4 KB

app/assets/images/emoji/blush.png 0 → 100755

5.07 KB

app/assets/images/emoji/boar.png 0 → 100755

4.73 KB

app/assets/images/emoji/boat.png 0 → 100755

3.74 KB

app/assets/images/emoji/bomb.png 0 → 100755

5.09 KB

app/assets/images/emoji/book.png 0 → 100755

5.91 KB

app/assets/images/emoji/bookmark.png 0 → 100755

4.59 KB

app/assets/images/emoji/bookmark_tabs.png 0 → 100755

3.09 KB

app/assets/images/emoji/books.png 0 → 100755

6.39 KB

app/assets/images/emoji/boot.png 0 → 100755

3.25 KB

app/assets/images/emoji/bouquet.png 0 → 100755

6.75 KB

app/assets/images/emoji/bow.png 0 → 100755

5.02 KB

app/assets/images/emoji/bowling.png 0 → 100755

4.09 KB

app/assets/images/emoji/bowtie.png 0 → 100755

6.33 KB

app/assets/images/emoji/boy.png 0 → 100755

5.81 KB

app/assets/images/emoji/bread.png 0 → 100755

6.07 KB

app/assets/images/emoji/bride_with_veil.png 0 → 100755

8.32 KB

app/assets/images/emoji/bridge_at_night.png 0 → 100755

5.02 KB

app/assets/images/emoji/briefcase.png 0 → 100755

2.63 KB

app/assets/images/emoji/broken_heart.png 0 → 100755

4.02 KB

app/assets/images/emoji/bug.png 0 → 100755

5.81 KB

app/assets/images/emoji/bulb.png 0 → 100755

4.38 KB

app/assets/images/emoji/bullettrain_front.png 0 → 100755

4.88 KB

app/assets/images/emoji/bullettrain_side.png 0 → 100755

3.75 KB

app/assets/images/emoji/bus.png 0 → 100755

3.97 KB

app/assets/images/emoji/busstop.png 0 → 100755

1.64 KB

app/assets/images/emoji/bust_in_silhouette.png 0 → 100755

1.96 KB

app/assets/images/emoji/busts_in_silhouette.png 0 → 100755

2.95 KB

app/assets/images/emoji/cactus.png 0 → 100755

4.4 KB

app/assets/images/emoji/cake.png 0 → 100755

5.99 KB

app/assets/images/emoji/calendar.png 0 → 100755

2.85 KB

app/assets/images/emoji/calling.png 0 → 100755

3.94 KB

app/assets/images/emoji/camel.png 0 → 100755

4.38 KB

app/assets/images/emoji/camera.png 0 → 100755

4.55 KB

app/assets/images/emoji/cancer.png 0 → 100755

5.26 KB

app/assets/images/emoji/candy.png 0 → 100755

4.4 KB

app/assets/images/emoji/capital_abcd.png 0 → 100755

5.02 KB

app/assets/images/emoji/capricorn.png 0 → 100755

4.56 KB

app/assets/images/emoji/car.png 0 → 100755

4.18 KB

app/assets/images/emoji/card_index.png 0 → 100755

3.66 KB

app/assets/images/emoji/carousel_horse.png 0 → 100755

5.75 KB

app/assets/images/emoji/cat.png 0 → 100755

5.85 KB

app/assets/images/emoji/cat2.png 0 → 100755

5.59 KB

app/assets/images/emoji/cd.png 0 → 100755

6.56 KB

app/assets/images/emoji/chart.png 0 → 100755

4.23 KB

app/assets/images/emoji/chart_with_downwards_trend.png 0 → 100755

2.84 KB

app/assets/images/emoji/chart_with_upwards_trend.png 0 → 100755

2.87 KB

app/assets/images/emoji/checkered_flag.png 0 → 100755

1.64 KB

app/assets/images/emoji/cherries.png 0 → 100755

5.47 KB

app/assets/images/emoji/cherry_blossom.png 0 → 100755

7.01 KB

app/assets/images/emoji/chestnut.png 0 → 100755

5.74 KB

app/assets/images/emoji/chicken.png 0 → 100755

3.89 KB

app/assets/images/emoji/children_crossing.png 0 → 100755

3.38 KB

app/assets/images/emoji/chocolate_bar.png 0 → 100755

5.13 KB

app/assets/images/emoji/christmas_tree.png 0 → 100755

4.61 KB

app/assets/images/emoji/church.png 0 → 100755

4.54 KB

app/assets/images/emoji/cinema.png 0 → 100755

3.49 KB

app/assets/images/emoji/circus_tent.png 0 → 100755

4.57 KB

app/assets/images/emoji/city_sunrise.png 0 → 100755

4.21 KB

app/assets/images/emoji/city_sunset.png 0 → 100755

3.75 KB

app/assets/images/emoji/cl.png 0 → 100755

3.41 KB

app/assets/images/emoji/clap.png 0 → 100755

6.94 KB

app/assets/images/emoji/clapper.png 0 → 100755

4.09 KB

app/assets/images/emoji/clipboard.png 0 → 100755

4.55 KB

app/assets/images/emoji/clock1.png 0 → 100755

2.53 KB

app/assets/images/emoji/clock10.png 0 → 100755

2.53 KB

app/assets/images/emoji/clock1030.png 0 → 100755

2.8 KB

app/assets/images/emoji/clock11.png 0 → 100755

2.53 KB

app/assets/images/emoji/clock1130.png 0 → 100755

2.79 KB

app/assets/images/emoji/clock12.png 0 → 100755

2.45 KB

app/assets/images/emoji/clock1230.png 0 → 100755

2.73 KB

app/assets/images/emoji/clock130.png 0 → 100755

2.78 KB

app/assets/images/emoji/clock2.png 0 → 100755

2.53 KB

app/assets/images/emoji/clock230.png 0 → 100755

2.79 KB

app/assets/images/emoji/clock3.png 0 → 100755

2.43 KB

app/assets/images/emoji/clock330.png 0 → 100755

2.67 KB

app/assets/images/emoji/clock4.png 0 → 100755

2.56 KB

app/assets/images/emoji/clock430.png 0 → 100755

2.78 KB

app/assets/images/emoji/clock5.png 0 → 100755

2.56 KB

app/assets/images/emoji/clock530.png 0 → 100755

2.77 KB

app/assets/images/emoji/clock6.png 0 → 100755

2.52 KB

app/assets/images/emoji/clock630.png 0 → 100755

2.67 KB

app/assets/images/emoji/clock7.png 0 → 100755

2.55 KB

app/assets/images/emoji/clock730.png 0 → 100755

2.75 KB

app/assets/images/emoji/clock8.png 0 → 100755

2.54 KB

app/assets/images/emoji/clock830.png 0 → 100755

2.78 KB

app/assets/images/emoji/clock9.png 0 → 100755

2.43 KB

app/assets/images/emoji/clock930.png 0 → 100755

2.68 KB

app/assets/images/emoji/closed_book.png 0 → 100755

4.73 KB

app/assets/images/emoji/closed_lock_with_key.png 0 → 100755

5.57 KB

app/assets/images/emoji/closed_umbrella.png 0 → 100755

3.78 KB

app/assets/images/emoji/cloud.png 0 → 100755

3.77 KB

app/assets/images/emoji/clubs.png 0 → 100755

1.65 KB

app/assets/images/emoji/cn.png 0 → 100755

3.55 KB

app/assets/images/emoji/cocktail.png 0 → 100755

2.88 KB

app/assets/images/emoji/coffee.png 0 → 100755

4.21 KB

app/assets/images/emoji/cold_sweat.png 0 → 100755

5.83 KB

app/assets/images/emoji/collision.png 0 → 100755

3.69 KB

app/assets/images/emoji/computer.png 0 → 100755

1.67 KB

app/assets/images/emoji/confetti_ball.png 0 → 100755

5.39 KB

app/assets/images/emoji/confounded.png 0 → 100755

5.72 KB

app/assets/images/emoji/congratulations.png 0 → 100755

4.77 KB

app/assets/images/emoji/construction.png 0 → 100755

3.61 KB

app/assets/images/emoji/construction_worker.png 0 → 100755

6.05 KB

app/assets/images/emoji/convenience_store.png 0 → 100755

3.98 KB

app/assets/images/emoji/cookie.png 0 → 100755

7.96 KB

app/assets/images/emoji/cool.png 0 → 100755

4.08 KB

app/assets/images/emoji/cop.png 0 → 100755

6.97 KB

app/assets/images/emoji/copyright.png 0 → 100755

1.54 KB

app/assets/images/emoji/corn.png 0 → 100755

6.54 KB

app/assets/images/emoji/couple.png 0 → 100755

7.44 KB

app/assets/images/emoji/couple_with_heart.png 0 → 100755

7.2 KB

app/assets/images/emoji/couplekiss.png 0 → 100755

7.05 KB

app/assets/images/emoji/cow.png 0 → 100755

5.61 KB

app/assets/images/emoji/cow2.png 0 → 100755

5.18 KB

app/assets/images/emoji/credit_card.png 0 → 100755

2.59 KB

app/assets/images/emoji/crocodile.png 0 → 100755

5.98 KB

app/assets/images/emoji/crossed_flags.png 0 → 100755

3.92 KB

app/assets/images/emoji/crown.png 0 → 100755

5.52 KB

app/assets/images/emoji/cry.png 0 → 100755

5.57 KB

app/assets/images/emoji/crying_cat_face.png 0 → 100755

6.53 KB

app/assets/images/emoji/crystal_ball.png 0 → 100755

6.09 KB

app/assets/images/emoji/cupid.png 0 → 100755

5.29 KB

app/assets/images/emoji/curly_loop.png 0 → 100755

1.23 KB

app/assets/images/emoji/currency_exchange.png 0 → 100755

1.91 KB

app/assets/images/emoji/curry.png 0 → 100755

5.21 KB

app/assets/images/emoji/custard.png 0 → 100755

5.67 KB

app/assets/images/emoji/customs.png 0 → 100755

3.81 KB

app/assets/images/emoji/cyclone.png 0 → 100755

4.78 KB

app/assets/images/emoji/dancer.png 0 → 100755

3.65 KB

app/assets/images/emoji/dancers.png 0 → 100755

7.73 KB

app/assets/images/emoji/dango.png 0 → 100755

4.34 KB

app/assets/images/emoji/dart.png 0 → 100755

5.33 KB

app/assets/images/emoji/dash.png 0 → 100755

5.32 KB

app/assets/images/emoji/date.png 0 → 100755

2.91 KB

app/assets/images/emoji/de.png 0 → 100755

2.58 KB

app/assets/images/emoji/deciduous_tree.png 0 → 100755

7.2 KB

app/assets/images/emoji/department_store.png 0 → 100755

5.04 KB

app/assets/images/emoji/diamond_shape_with_a_dot_inside.png 0 → 100755

5.56 KB

app/assets/images/emoji/diamonds.png 0 → 100755

2.72 KB

app/assets/images/emoji/disappointed.png 0 → 100755

4.65 KB

app/assets/images/emoji/dizzy.png 0 → 100755

2.97 KB

app/assets/images/emoji/dizzy_face.png 0 → 100755

6.13 KB

app/assets/images/emoji/do_not_litter.png 0 → 100755

5.15 KB

app/assets/images/emoji/dog.png 0 → 100755

5.81 KB

app/assets/images/emoji/dog2.png 0 → 100755

5.79 KB

app/assets/images/emoji/dollar.png 0 → 100755

4.51 KB

app/assets/images/emoji/dolls.png 0 → 100755

6.97 KB

app/assets/images/emoji/dolphin.png 0 → 100755

4.24 KB

app/assets/images/emoji/door.png 0 → 100755

3.23 KB

app/assets/images/emoji/doughnut.png 0 → 100755

5.09 KB

app/assets/images/emoji/dragon.png 0 → 100755

7.64 KB

app/assets/images/emoji/dragon_face.png 0 → 100755

6.58 KB

app/assets/images/emoji/dress.png 0 → 100755

3.55 KB

app/assets/images/emoji/dromedary_camel.png 0 → 100755

5.02 KB

app/assets/images/emoji/droplet.png 0 → 100755

3.2 KB

app/assets/images/emoji/dvd.png 0 → 100755

6.83 KB

app/assets/images/emoji/e-mail.png 0 → 100755

2.08 KB

app/assets/images/emoji/ear.png 0 → 100755

4.23 KB

app/assets/images/emoji/ear_of_rice.png 0 → 100755

4.65 KB

app/assets/images/emoji/earth_africa.png 0 → 100755

7 KB

app/assets/images/emoji/earth_americas.png 0 → 100755

6.87 KB

app/assets/images/emoji/earth_asia.png 0 → 100755

7.13 KB

app/assets/images/emoji/egg.png 0 → 100755

5.09 KB

app/assets/images/emoji/eggplant.png 0 → 100755

4.56 KB

app/assets/images/emoji/eight.png 0 → 100755

3.75 KB

app/assets/images/emoji/eight_pointed_black_star.png 0 → 100755

3.21 KB

app/assets/images/emoji/eight_spoked_asterisk.png 0 → 100755

3.92 KB

app/assets/images/emoji/electric_plug.png 0 → 100755

2.75 KB

app/assets/images/emoji/elephant.png 0 → 100755

4.97 KB

app/assets/images/emoji/email.png 0 → 100755

2.63 KB

app/assets/images/emoji/end.png 0 → 100755

1.44 KB

app/assets/images/emoji/envelope.png 0 → 100755

1.62 KB

app/assets/images/emoji/es.png 0 → 100755

4.2 KB

app/assets/images/emoji/euro.png 0 → 100755

3.85 KB

app/assets/images/emoji/european_castle.png 0 → 100755

5.3 KB

app/assets/images/emoji/european_post_office.png 0 → 100755

4.7 KB

app/assets/images/emoji/evergreen_tree.png 0 → 100755

4.81 KB

app/assets/images/emoji/exclamation.png 0 → 100755

1.15 KB

app/assets/images/emoji/eyeglasses.png 0 → 100755

4.81 KB

app/assets/images/emoji/eyes.png 0 → 100755

4.29 KB

app/assets/images/emoji/facepunch.png 0 → 100755

4.76 KB

app/assets/images/emoji/factory.png 0 → 100755

5.43 KB

app/assets/images/emoji/fallen_leaf.png 0 → 100755

4.78 KB

app/assets/images/emoji/family.png 0 → 100755

7.04 KB

app/assets/images/emoji/fast_forward.png 0 → 100755

3.03 KB

app/assets/images/emoji/fax.png 0 → 100755

4.54 KB

app/assets/images/emoji/fearful.png 0 → 100755

5.47 KB

app/assets/images/emoji/feelsgood.png 0 → 100755

1.12 KB

app/assets/images/emoji/feet.png 0 → 100755

1.49 KB

app/assets/images/emoji/ferris_wheel.png 0 → 100755

6.07 KB

app/assets/images/emoji/file_folder.png 0 → 100755

3.92 KB

app/assets/images/emoji/finnadie.png 0 → 100755

1.16 KB

app/assets/images/emoji/fire.png 0 → 100755

3.79 KB

app/assets/images/emoji/fire_engine.png 0 → 100755

4.75 KB

app/assets/images/emoji/fireworks.png 0 → 100755

6.12 KB

app/assets/images/emoji/first_quarter_moon.png 0 → 100755

5.83 KB

app/assets/images/emoji/first_quarter_moon_with_face.png 0 → 100755

4.18 KB

app/assets/images/emoji/fish.png 0 → 100755

4.61 KB

app/assets/images/emoji/fish_cake.png 0 → 100755

5.68 KB

app/assets/images/emoji/fishing_pole_and_fish.png 0 → 100755

4.37 KB

app/assets/images/emoji/fist.png 0 → 100755

5.74 KB

app/assets/images/emoji/five.png 0 → 100755

3.51 KB

app/assets/images/emoji/flags.png 0 → 100755

5.98 KB

app/assets/images/emoji/flashlight.png 0 → 100755

4.91 KB

app/assets/images/emoji/floppy_disk.png 0 → 100755

3.14 KB

app/assets/images/emoji/flower_playing_cards.png 0 → 100755

3.35 KB

app/assets/images/emoji/flushed.png 0 → 100755

5.71 KB

app/assets/images/emoji/foggy.png 0 → 100755

4.51 KB

app/assets/images/emoji/football.png 0 → 100755

6.55 KB

app/assets/images/emoji/fork_and_knife.png 0 → 100755

3.52 KB

app/assets/images/emoji/fountain.png 0 → 100755

4.97 KB

app/assets/images/emoji/four.png 0 → 100755

3.1 KB

app/assets/images/emoji/four_leaf_clover.png 0 → 100755

5.85 KB

app/assets/images/emoji/fr.png 0 → 100755

3.32 KB

app/assets/images/emoji/free.png 0 → 100755

3.52 KB

app/assets/images/emoji/fried_shrimp.png 0 → 100755

7.37 KB

app/assets/images/emoji/fries.png 0 → 100755

6.25 KB

app/assets/images/emoji/frog.png 0 → 100755

4.71 KB

app/assets/images/emoji/fuelpump.png 0 → 100755

4.2 KB

app/assets/images/emoji/full_moon.png 0 → 100755

6.31 KB

app/assets/images/emoji/full_moon_with_face.png 0 → 100755

7.05 KB

app/assets/images/emoji/game_die.png 0 → 100755

2.89 KB

app/assets/images/emoji/gb.png 0 → 100755

5.76 KB

app/assets/images/emoji/gem.png 0 → 100755

4.74 KB

app/assets/images/emoji/gemini.png 0 → 100755

4.2 KB

app/assets/images/emoji/ghost.png 0 → 100755

4.41 KB

app/assets/images/emoji/gift.png 0 → 100755

6.55 KB

app/assets/images/emoji/gift_heart.png 0 → 100755

5.87 KB

app/assets/images/emoji/girl.png 0 → 100755

6.17 KB

app/assets/images/emoji/globe_with_meridians.png 0 → 100755

5.7 KB

app/assets/images/emoji/goat.png 0 → 100755

4.77 KB

app/assets/images/emoji/goberserk.png 0 → 100755

1.3 KB

app/assets/images/emoji/godmode.png 0 → 100755

1.02 KB

app/assets/images/emoji/golf.png 0 → 100755

3.46 KB

app/assets/images/emoji/grapes.png 0 → 100755

5.3 KB

app/assets/images/emoji/green_apple.png 0 → 100755

6.06 KB

app/assets/images/emoji/green_book.png 0 → 100755

4.97 KB

app/assets/images/emoji/green_heart.png 0 → 100755

4.33 KB

app/assets/images/emoji/grey_exclamation.png 0 → 100755

1.12 KB

app/assets/images/emoji/grey_question.png 0 → 100755

1.03 KB

app/assets/images/emoji/grin.png 0 → 100755

5.59 KB

app/assets/images/emoji/guardsman.png 0 → 100755

3.5 KB

app/assets/images/emoji/guitar.png 0 → 100755

4.28 KB

app/assets/images/emoji/gun.png 0 → 100755

3.09 KB

app/assets/images/emoji/haircut.png 0 → 100755

6.93 KB

app/assets/images/emoji/hamburger.png 0 → 100755

5.57 KB

app/assets/images/emoji/hammer.png 0 → 100755

3.58 KB

app/assets/images/emoji/hamster.png 0 → 100755

7.05 KB

app/assets/images/emoji/hand.png 0 → 100755

4.06 KB

app/assets/images/emoji/handbag.png 0 → 100755

5.32 KB

app/assets/images/emoji/hankey.png 0 → 100755

4.64 KB

app/assets/images/emoji/hash.png 0 → 100755

3.65 KB

app/assets/images/emoji/hatched_chick.png 0 → 100755

5.51 KB

app/assets/images/emoji/hatching_chick.png 0 → 100755

5.79 KB

app/assets/images/emoji/headphones.png 0 → 100755

1.87 KB

app/assets/images/emoji/hear_no_evil.png 0 → 100755

6.4 KB

app/assets/images/emoji/heart.png 0 → 100755

3.22 KB

app/assets/images/emoji/heart_decoration.png 0 → 100755

3.42 KB

app/assets/images/emoji/heart_eyes.png 0 → 100755

5.62 KB

app/assets/images/emoji/heart_eyes_cat.png 0 → 100755

6.03 KB

app/assets/images/emoji/heartbeat.png 0 → 100755

3.96 KB

app/assets/images/emoji/heartpulse.png 0 → 100755

6.12 KB

app/assets/images/emoji/hearts.png 0 → 100755

2.86 KB

app/assets/images/emoji/heavy_check_mark.png 0 → 100755

1.08 KB

app/assets/images/emoji/heavy_division_sign.png 0 → 100755

340 Bytes

app/assets/images/emoji/heavy_dollar_sign.png 0 → 100755

1.38 KB

app/assets/images/emoji/heavy_exclamation_mark.png 0 → 100755

1.28 KB

app/assets/images/emoji/heavy_minus_sign.png 0 → 100755

197 Bytes

app/assets/images/emoji/heavy_multiplication_x.png 0 → 100755

591 Bytes

app/assets/images/emoji/heavy_plus_sign.png 0 → 100755

315 Bytes

app/assets/images/emoji/helicopter.png 0 → 100755

4 KB

app/assets/images/emoji/herb.png 0 → 100755

5.75 KB

app/assets/images/emoji/hibiscus.png 0 → 100755

8.13 KB

app/assets/images/emoji/high_brightness.png 0 → 100755

3.96 KB

app/assets/images/emoji/high_heel.png 0 → 100755

4.45 KB

app/assets/images/emoji/hocho.png 0 → 100755

2.45 KB

app/assets/images/emoji/honey_pot.png 0 → 100755

5.69 KB

app/assets/images/emoji/honeybee.png 0 → 100755

5.71 KB

app/assets/images/emoji/horse.png 0 → 100755

4.47 KB

app/assets/images/emoji/horse_racing.png 0 → 100755

5.77 KB

app/assets/images/emoji/hospital.png 0 → 100755

4.77 KB

app/assets/images/emoji/hotel.png 0 → 100755

5 KB

app/assets/images/emoji/hotsprings.png 0 → 100755

3.46 KB

app/assets/images/emoji/hourglass.png 0 → 100755

4.39 KB

app/assets/images/emoji/house.png 0 → 100755

3.43 KB

app/assets/images/emoji/hurtrealbad.png 0 → 100755

1.42 KB

app/assets/images/emoji/ice_cream.png 0 → 100755

5.34 KB

app/assets/images/emoji/icecream.png 0 → 100755

4.5 KB

app/assets/images/emoji/id.png 0 → 100755

3.81 KB

app/assets/images/emoji/ideograph_advantage.png 0 → 100755

3.02 KB

app/assets/images/emoji/imp.png 0 → 100755

6.48 KB

app/assets/images/emoji/inbox_tray.png 0 → 100755

3.61 KB

app/assets/images/emoji/incoming_envelope.png 0 → 100755

2.15 KB

app/assets/images/emoji/information_desk_person.png 0 → 100755

6.45 KB

app/assets/images/emoji/information_source.png 0 → 100755

3.58 KB

app/assets/images/emoji/innocent.png 0 → 100755

6.84 KB

app/assets/images/emoji/interrobang.png 0 → 100755

2.81 KB

app/assets/images/emoji/iphone.png 0 → 100755

3.42 KB

app/assets/images/emoji/it.png 0 → 100755

3.41 KB

app/assets/images/emoji/izakaya_lantern.png 0 → 100755

3.97 KB

app/assets/images/emoji/jack_o_lantern.png 0 → 100755

5.5 KB

app/assets/images/emoji/japan.png 0 → 100755

3.99 KB

app/assets/images/emoji/japanese_castle.png 0 → 100755

4.82 KB

app/assets/images/emoji/japanese_goblin.png 0 → 100755

5.04 KB

app/assets/images/emoji/japanese_ogre.png 0 → 100755

6.98 KB

app/assets/images/emoji/jeans.png 0 → 100755

3.39 KB

app/assets/images/emoji/joy.png 0 → 100755

6.19 KB

app/assets/images/emoji/joy_cat.png 0 → 100755

7.02 KB

app/assets/images/emoji/jp.png 0 → 100755

2.76 KB

app/assets/images/emoji/key.png 0 → 100755

3.37 KB

app/assets/images/emoji/keycap_ten.png 0 → 100755

4 KB

app/assets/images/emoji/kimono.png 0 → 100755

4.82 KB

app/assets/images/emoji/kiss.png 0 → 100755

6.13 KB

app/assets/images/emoji/kissing_cat.png 0 → 100755

6.64 KB

app/assets/images/emoji/kissing_face.png 0 → 100755

5.43 KB

app/assets/images/emoji/kissing_heart.png 0 → 100755

5.63 KB

app/assets/images/emoji/koala.png 0 → 100755

5.55 KB

app/assets/images/emoji/koko.png 0 → 100755

2.79 KB

app/assets/images/emoji/kr.png 0 → 100755

4.99 KB

app/assets/images/emoji/large_blue_circle.png 0 → 100755

4.53 KB

app/assets/images/emoji/large_blue_diamond.png 0 → 100755

3.7 KB

app/assets/images/emoji/large_orange_diamond.png 0 → 100755

3.81 KB

app/assets/images/emoji/last_quarter_moon.png 0 → 100755

6.03 KB

app/assets/images/emoji/last_quarter_moon_with_face.png 0 → 100755

4.23 KB

app/assets/images/emoji/laughing.png 0 → 100755

6.2 KB

app/assets/images/emoji/leaves.png 0 → 100755

5.44 KB

app/assets/images/emoji/ledger.png 0 → 100755

5.78 KB

app/assets/images/emoji/left_luggage.png 0 → 100755

3.93 KB

app/assets/images/emoji/left_right_arrow.png 0 → 100755

3.33 KB

app/assets/images/emoji/leftwards_arrow_with_hook.png 0 → 100755

3.69 KB

app/assets/images/emoji/lemon.png 0 → 100755

5.91 KB

app/assets/images/emoji/leo.png 0 → 100755

4.8 KB

app/assets/images/emoji/leopard.png 0 → 100755

5.26 KB

app/assets/images/emoji/libra.png 0 → 100755

4.13 KB

app/assets/images/emoji/light_rail.png 0 → 100755

3.7 KB

app/assets/images/emoji/link.png 0 → 100755

2.59 KB

app/assets/images/emoji/lips.png 0 → 100755

3.65 KB

app/assets/images/emoji/lipstick.png 0 → 100755

3.3 KB

app/assets/images/emoji/lock.png 0 → 100755

3.59 KB

app/assets/images/emoji/lock_with_ink_pen.png 0 → 100755

4.85 KB

app/assets/images/emoji/lollipop.png 0 → 100755

5.64 KB

app/assets/images/emoji/loop.png 0 → 100755

3.34 KB

app/assets/images/emoji/loudspeaker.png 0 → 100755

5.86 KB

app/assets/images/emoji/love_hotel.png 0 → 100755

5.8 KB

app/assets/images/emoji/love_letter.png 0 → 100755

2.41 KB

app/assets/images/emoji/low_brightness.png 0 → 100755

2.44 KB

app/assets/images/emoji/m.png 0 → 100755

4.63 KB

app/assets/images/emoji/mag.png 0 → 100755

2.97 KB

app/assets/images/emoji/mag_right.png 0 → 100755

3.54 KB

app/assets/images/emoji/mahjong.png 0 → 100755

3.23 KB

app/assets/images/emoji/mailbox.png 0 → 100755

4.1 KB

app/assets/images/emoji/mailbox_closed.png 0 → 100755

4.26 KB

app/assets/images/emoji/mailbox_with_mail.png 0 → 100755

4.47 KB

app/assets/images/emoji/mailbox_with_no_mail.png 0 → 100755

3.03 KB

app/assets/images/emoji/man.png 0 → 100755

5.88 KB

app/assets/images/emoji/man_with_gua_pi_mao.png 0 → 100755

5.2 KB

app/assets/images/emoji/man_with_turban.png 0 → 100755

6.38 KB

app/assets/images/emoji/mans_shoe.png 0 → 100755

4.64 KB

app/assets/images/emoji/maple_leaf.png 0 → 100755

4.35 KB

app/assets/images/emoji/mask.png 0 → 100755

5.11 KB

app/assets/images/emoji/massage.png 0 → 100755

5.89 KB

app/assets/images/emoji/meat_on_bone.png 0 → 100755

5.4 KB

app/assets/images/emoji/mega.png 0 → 100755

4.57 KB

app/assets/images/emoji/melon.png 0 → 100755

8.04 KB

app/assets/images/emoji/memo.png 0 → 100755

4.83 KB

app/assets/images/emoji/mens.png 0 → 100755

3.29 KB

app/assets/images/emoji/metal.png 0 → 100755

3.03 KB

app/assets/images/emoji/metro.png 0 → 100755

3.32 KB

app/assets/images/emoji/microphone.png 0 → 100755

3.59 KB

app/assets/images/emoji/microscope.png 0 → 100755

4.04 KB

app/assets/images/emoji/milky_way.png 0 → 100755

5.74 KB

app/assets/images/emoji/minibus.png 0 → 100755

3.04 KB

app/assets/images/emoji/minidisc.png 0 → 100755

5.46 KB

app/assets/images/emoji/mobile_phone_off.png 0 → 100755

3.44 KB

app/assets/images/emoji/money_with_wings.png 0 → 100755

7.41 KB

app/assets/images/emoji/moneybag.png 0 → 100755

5.37 KB

app/assets/images/emoji/monkey.png 0 → 100755

4.86 KB

app/assets/images/emoji/monkey_face.png 0 → 100755

5.22 KB

app/assets/images/emoji/monorail.png 0 → 100755

4.21 KB

app/assets/images/emoji/moon.png 0 → 100755

3.46 KB

app/assets/images/emoji/mortar_board.png 0 → 100755

4.07 KB

app/assets/images/emoji/mount_fuji.png 0 → 100755

4.89 KB

app/assets/images/emoji/mountain_bicyclist.png 0 → 100755

9.29 KB

app/assets/images/emoji/mountain_cableway.png 0 → 100755

4.3 KB

app/assets/images/emoji/mountain_railway.png 0 → 100755

7.27 KB

app/assets/images/emoji/mouse.png 0 → 100755

6.47 KB

app/assets/images/emoji/mouse2.png 0 → 100755

3.99 KB

app/assets/images/emoji/movie_camera.png 0 → 100755

3.99 KB

app/assets/images/emoji/moyai.png 0 → 100755

2.12 KB

app/assets/images/emoji/muscle.png 0 → 100755

4.56 KB

app/assets/images/emoji/mushroom.png 0 → 100755

4.77 KB

app/assets/images/emoji/musical_keyboard.png 0 → 100755

1.9 KB

app/assets/images/emoji/musical_note.png 0 → 100755

3.11 KB

app/assets/images/emoji/musical_score.png 0 → 100755

1.54 KB

app/assets/images/emoji/mute.png 0 → 100755

6.48 KB

app/assets/images/emoji/nail_care.png 0 → 100755

5.68 KB

app/assets/images/emoji/name_badge.png 0 → 100755

3.89 KB

app/assets/images/emoji/neckbeard.png 0 → 100755

6.27 KB

app/assets/images/emoji/necktie.png 0 → 100755

5.97 KB

app/assets/images/emoji/negative_squared_cross_mark.png 0 → 100755

3.76 KB

app/assets/images/emoji/neutral_face.png 0 → 100755

4.73 KB

app/assets/images/emoji/new.png 0 → 100755

3.83 KB

app/assets/images/emoji/new_moon.png 0 → 100755

5.25 KB

app/assets/images/emoji/new_moon_with_face.png 0 → 100755

6.59 KB

app/assets/images/emoji/newspaper.png 0 → 100755

5.08 KB

app/assets/images/emoji/ng.png 0 → 100755

4.1 KB

app/assets/images/emoji/nine.png 0 → 100755

3.69 KB

app/assets/images/emoji/no_bell.png 0 → 100755

5.8 KB

app/assets/images/emoji/no_bicycles.png 0 → 100755

5.53 KB

app/assets/images/emoji/no_entry.png 0 → 100755

3.43 KB

app/assets/images/emoji/no_entry_sign.png 0 → 100755

3.21 KB

app/assets/images/emoji/no_good.png 0 → 100755

6.87 KB

app/assets/images/emoji/no_mobile_phones.png 0 → 100755

4.96 KB

app/assets/images/emoji/no_mouth.png 0 → 100755

4.62 KB

app/assets/images/emoji/no_pedestrians.png 0 → 100755

5.36 KB

app/assets/images/emoji/no_smoking.png 0 → 100755

4.11 KB

app/assets/images/emoji/non-potable_water.png 0 → 100755

5.08 KB

app/assets/images/emoji/nose.png 0 → 100755

3.62 KB

app/assets/images/emoji/notebook.png 0 → 100755

5.89 KB

app/assets/images/emoji/notebook_with_decorative_cover.png 0 → 100755

5.2 KB

app/assets/images/emoji/notes.png 0 → 100755

1.5 KB

app/assets/images/emoji/nut_and_bolt.png 0 → 100755

2.12 KB

app/assets/images/emoji/o.png 0 → 100755

2.48 KB

app/assets/images/emoji/o2.png 0 → 100755

3.42 KB

app/assets/images/emoji/ocean.png 0 → 100755

5.64 KB

app/assets/images/emoji/octocat.png 0 → 100755

3.84 KB

app/assets/images/emoji/octopus.png 0 → 100755

5.64 KB

app/assets/images/emoji/oden.png 0 → 100755

5.41 KB

app/assets/images/emoji/office.png 0 → 100755

5.04 KB

app/assets/images/emoji/ok.png 0 → 100755

4.06 KB

app/assets/images/emoji/ok_hand.png 0 → 100755

4.49 KB

app/assets/images/emoji/ok_woman.png 0 → 100755

7.35 KB

app/assets/images/emoji/older_man.png 0 → 100755

6.58 KB

app/assets/images/emoji/older_woman.png 0 → 100755

5.84 KB

app/assets/images/emoji/on.png 0 → 100755

1.76 KB

app/assets/images/emoji/oncoming_automobile.png 0 → 100755

7.29 KB

app/assets/images/emoji/oncoming_bus.png 0 → 100755

5.18 KB

app/assets/images/emoji/oncoming_police_car.png 0 → 100755

5.55 KB

app/assets/images/emoji/oncoming_taxi.png 0 → 100755

6.14 KB

app/assets/images/emoji/one.png 0 → 100755

2.76 KB

app/assets/images/emoji/open_file_folder.png 0 → 100755

4.19 KB

app/assets/images/emoji/open_hands.png 0 → 100755

4.83 KB

app/assets/images/emoji/ophiuchus.png 0 → 100755

4.33 KB

app/assets/images/emoji/orange_book.png 0 → 100755

4.97 KB

app/assets/images/emoji/outbox_tray.png 0 → 100755

3.6 KB

app/assets/images/emoji/ox.png 0 → 100755

5.94 KB

app/assets/images/emoji/page_facing_up.png 0 → 100755

2.13 KB

app/assets/images/emoji/page_with_curl.png 0 → 100755

3.64 KB

app/assets/images/emoji/pager.png 0 → 100755

3.93 KB

app/assets/images/emoji/palm_tree.png 0 → 100755

3.58 KB

app/assets/images/emoji/panda_face.png 0 → 100755

4.7 KB

app/assets/images/emoji/paperclip.png 0 → 100755

2.5 KB

app/assets/images/emoji/parking.png 0 → 100755

3.01 KB

app/assets/images/emoji/part_alternation_mark.png 0 → 100755

2.62 KB

app/assets/images/emoji/partly_sunny.png 0 → 100755

5.06 KB

app/assets/images/emoji/passport_control.png 0 → 100755

3.92 KB

app/assets/images/emoji/paw_prints.png 0 → 100755

2.41 KB

app/assets/images/emoji/peach.png 0 → 100755

5.78 KB

app/assets/images/emoji/pear.png 0 → 100755

6.77 KB

app/assets/images/emoji/pencil.png 0 → 100755

4.83 KB

app/assets/images/emoji/pencil2.png 0 → 100755

4.35 KB

app/assets/images/emoji/penguin.png 0 → 100755

4.63 KB

app/assets/images/emoji/pensive.png 0 → 100755

4.94 KB

app/assets/images/emoji/performing_arts.png 0 → 100755

6.14 KB

app/assets/images/emoji/persevere.png 0 → 100755

5.39 KB

app/assets/images/emoji/person_frowning.png 0 → 100755

4.71 KB

app/assets/images/emoji/person_with_blond_hair.png 0 → 100755

6.47 KB

app/assets/images/emoji/person_with_pouting_face.png 0 → 100755

5.3 KB

app/assets/images/emoji/phone.png 0 → 100755

5.37 KB

app/assets/images/emoji/pig.png 0 → 100755

5.86 KB

app/assets/images/emoji/pig2.png 0 → 100755

4.68 KB

app/assets/images/emoji/pig_nose.png 0 → 100755

4.65 KB

app/assets/images/emoji/pill.png 0 → 100755

4.9 KB

app/assets/images/emoji/pineapple.png 0 → 100755

5.5 KB

app/assets/images/emoji/pisces.png 0 → 100755

4.35 KB

app/assets/images/emoji/pizza.png 0 → 100755

5.15 KB

app/assets/images/emoji/plus1.png 0 → 100755

4.96 KB

app/assets/images/emoji/point_down.png 0 → 100755

3.15 KB

app/assets/images/emoji/point_left.png 0 → 100755

3.01 KB

app/assets/images/emoji/point_right.png 0 → 100755

3.01 KB

app/assets/images/emoji/point_up.png 0 → 100755

3.35 KB

app/assets/images/emoji/point_up_2.png 0 → 100755

3.11 KB

app/assets/images/emoji/police_car.png 0 → 100755

3.27 KB

app/assets/images/emoji/poodle.png 0 → 100755

6.69 KB

app/assets/images/emoji/poop.png 0 → 100755

4.64 KB

app/assets/images/emoji/post_office.png 0 → 100755

5.02 KB

app/assets/images/emoji/postal_horn.png 0 → 100755

4.71 KB

app/assets/images/emoji/postbox.png 0 → 100755

3.31 KB

app/assets/images/emoji/potable_water.png 0 → 100755

3.84 KB

app/assets/images/emoji/pouch.png 0 → 100755

4.58 KB

app/assets/images/emoji/poultry_leg.png 0 → 100755

4.1 KB

app/assets/images/emoji/pound.png 0 → 100755

4.14 KB

app/assets/images/emoji/pouting_cat.png 0 → 100755

4.8 KB

app/assets/images/emoji/pray.png 0 → 100755

6.06 KB

app/assets/images/emoji/princess.png 0 → 100755

7.73 KB

app/assets/images/emoji/punch.png 0 → 100755

4.72 KB

app/assets/images/emoji/purple_heart.png 0 → 100755

4.19 KB

app/assets/images/emoji/purse.png 0 → 100755

4.92 KB

app/assets/images/emoji/pushpin.png 0 → 100755

3.7 KB

app/assets/images/emoji/put_litter_in_its_place.png 0 → 100755

4 KB

app/assets/images/emoji/question.png 0 → 100755

1.67 KB

app/assets/images/emoji/rabbit.png 0 → 100755

5.54 KB

app/assets/images/emoji/rabbit2.png 0 → 100755

4.41 KB

app/assets/images/emoji/racehorse.png 0 → 100755

4.62 KB

app/assets/images/emoji/radio.png 0 → 100755

6.01 KB

app/assets/images/emoji/radio_button.png 0 → 100755

2.15 KB

app/assets/images/emoji/rage.png 0 → 100755

5.28 KB

app/assets/images/emoji/rage1.png 0 → 100755

1.06 KB

app/assets/images/emoji/rage2.png 0 → 100755

1.07 KB

app/assets/images/emoji/rage3.png 0 → 100755

1.09 KB

app/assets/images/emoji/rage4.png 0 → 100755

1.24 KB

app/assets/images/emoji/railway_car.png 0 → 100755

3.56 KB

app/assets/images/emoji/rainbow.png 0 → 100755

5.19 KB

app/assets/images/emoji/raised_hand.png 0 → 100755

6.03 KB

app/assets/images/emoji/raised_hands.png 0 → 100755

5.25 KB

app/assets/images/emoji/ram.png 0 → 100755

6.38 KB

app/assets/images/emoji/ramen.png 0 → 100755

6.42 KB

app/assets/images/emoji/rat.png 0 → 100755

5.31 KB

app/assets/images/emoji/recycle.png 0 → 100755

3.62 KB

app/assets/images/emoji/red_car.png 0 → 100755

4.18 KB

app/assets/images/emoji/red_circle.png 0 → 100755

3.85 KB

app/assets/images/emoji/registered.png 0 → 100755

1.58 KB

app/assets/images/emoji/relaxed.png 0 → 100755

5.33 KB

app/assets/images/emoji/relieved.png 0 → 100755

5.52 KB

app/assets/images/emoji/repeat.png 0 → 100755

3.92 KB

app/assets/images/emoji/repeat_one.png 0 → 100755

4.19 KB

app/assets/images/emoji/restroom.png 0 → 100755

4.04 KB

app/assets/images/emoji/revolving_hearts.png 0 → 100755

5.34 KB

app/assets/images/emoji/rewind.png 0 → 100755

2.98 KB

app/assets/images/emoji/ribbon.png 0 → 100755

5.45 KB

app/assets/images/emoji/rice.png 0 → 100755

4.54 KB

app/assets/images/emoji/rice_ball.png 0 → 100755

5.28 KB

app/assets/images/emoji/rice_cracker.png 0 → 100755

7.6 KB

app/assets/images/emoji/rice_scene.png 0 → 100755

6.11 KB

app/assets/images/emoji/ring.png 0 → 100755

5.11 KB

app/assets/images/emoji/rocket.png 0 → 100755

5.26 KB

app/assets/images/emoji/roller_coaster.png 0 → 100755

5.03 KB

app/assets/images/emoji/rooster.png 0 → 100755

6.02 KB

app/assets/images/emoji/rose.png 0 → 100755

4.1 KB

app/assets/images/emoji/rotating_light.png 0 → 100755

6.46 KB

app/assets/images/emoji/round_pushpin.png 0 → 100755

1.89 KB

app/assets/images/emoji/rowboat.png 0 → 100755

5.31 KB

app/assets/images/emoji/ru.png 0 → 100755

3.83 KB

app/assets/images/emoji/rugby_football.png 0 → 100755

7.6 KB

app/assets/images/emoji/runner.png 0 → 100755

3.06 KB

app/assets/images/emoji/running.png 0 → 100755

3.14 KB

app/assets/images/emoji/running_shirt_with_sash.png 0 → 100755

5.57 KB

app/assets/images/emoji/sa.png 0 → 100755

3.47 KB

app/assets/images/emoji/sagittarius.png 0 → 100755

4.4 KB

app/assets/images/emoji/sailboat.png 0 → 100755

3.74 KB

app/assets/images/emoji/sake.png 0 → 100755

4.95 KB

app/assets/images/emoji/sandal.png 0 → 100755

3.88 KB

app/assets/images/emoji/santa.png 0 → 100755

6.12 KB

app/assets/images/emoji/satellite.png 0 → 100755

4.75 KB

app/assets/images/emoji/satisfied.png 0 → 100755

5.24 KB

app/assets/images/emoji/saxophone.png 0 → 100755

4.15 KB

app/assets/images/emoji/school.png 0 → 100755

5.32 KB

app/assets/images/emoji/school_satchel.png 0 → 100755

5.61 KB

app/assets/images/emoji/scissors.png 0 → 100755

3.75 KB

app/assets/images/emoji/scorpius.png 0 → 100755

4.46 KB

app/assets/images/emoji/scream.png 0 → 100755

6.33 KB

app/assets/images/emoji/scream_cat.png 0 → 100755

6.68 KB

app/assets/images/emoji/scroll.png 0 → 100755

6.59 KB

app/assets/images/emoji/seat.png 0 → 100755

5.92 KB

app/assets/images/emoji/secret.png 0 → 100755

5.24 KB

app/assets/images/emoji/see_no_evil.png 0 → 100755

6.67 KB

app/assets/images/emoji/seedling.png 0 → 100755

2.21 KB

app/assets/images/emoji/seven.png 0 → 100755

2.98 KB

app/assets/images/emoji/shaved_ice.png 0 → 100755

5.77 KB

app/assets/images/emoji/sheep.png 0 → 100755

4.62 KB

app/assets/images/emoji/shell.png 0 → 100755

5 KB

app/assets/images/emoji/ship.png 0 → 100755

4.13 KB

app/assets/images/emoji/shipit.png 0 → 100755

9.13 KB

app/assets/images/emoji/shirt.png 0 → 100755

4.57 KB

app/assets/images/emoji/shit.png 0 → 100755

4.64 KB

app/assets/images/emoji/shoe.png 0 → 100755

4.69 KB

app/assets/images/emoji/shower.png 0 → 100755

7.41 KB

app/assets/images/emoji/signal_strength.png 0 → 100755

3.16 KB

app/assets/images/emoji/six.png 0 → 100755

3.7 KB

app/assets/images/emoji/six_pointed_star.png 0 → 100755

4.75 KB

app/assets/images/emoji/ski.png 0 → 100755

4.07 KB

app/assets/images/emoji/skull.png 0 → 100755

2.37 KB

app/assets/images/emoji/sleepy.png 0 → 100755

5.7 KB

app/assets/images/emoji/slot_machine.png 0 → 100755

4.5 KB

app/assets/images/emoji/small_blue_diamond.png 0 → 100755

1.85 KB

app/assets/images/emoji/small_orange_diamond.png 0 → 100755

1.9 KB

app/assets/images/emoji/small_red_triangle.png 0 → 100755

2.01 KB

app/assets/images/emoji/small_red_triangle_down.png 0 → 100755

2.11 KB

app/assets/images/emoji/smile.png 0 → 100755

5.75 KB

app/assets/images/emoji/smile_cat.png 0 → 100755

5.97 KB

app/assets/images/emoji/smiley.png 0 → 100755

5.66 KB

app/assets/images/emoji/smiley_cat.png 0 → 100755

5.94 KB

app/assets/images/emoji/smiling_imp.png 0 → 100755

7.02 KB

app/assets/images/emoji/smirk.png 0 → 100755

5.18 KB

app/assets/images/emoji/smirk_cat.png 0 → 100755

5.92 KB

app/assets/images/emoji/smoking.png 0 → 100755

2.81 KB

app/assets/images/emoji/snail.png 0 → 100755

6.5 KB

app/assets/images/emoji/snake.png 0 → 100755

3.97 KB

app/assets/images/emoji/snowboarder.png 0 → 100755

5.23 KB

app/assets/images/emoji/snowflake.png 0 → 100755

5.5 KB

app/assets/images/emoji/snowman.png 0 → 100755

4.55 KB

app/assets/images/emoji/sob.png 0 → 100755

5.58 KB

app/assets/images/emoji/soccer.png 0 → 100755

4.76 KB

app/assets/images/emoji/soon.png 0 → 100755

1.87 KB

app/assets/images/emoji/sos.png 0 → 100755

4.16 KB

app/assets/images/emoji/sound.png 0 → 100755

4.91 KB

app/assets/images/emoji/space_invader.png 0 → 100755

4.25 KB

app/assets/images/emoji/spades.png 0 → 100755

1.68 KB

app/assets/images/emoji/spaghetti.png 0 → 100755

6.79 KB

app/assets/images/emoji/sparkler.png 0 → 100755

5.56 KB

app/assets/images/emoji/sparkles.png 0 → 100755

2.16 KB

app/assets/images/emoji/speak_no_evil.png 0 → 100755

5.84 KB

app/assets/images/emoji/speaker.png 0 → 100755

5.05 KB

app/assets/images/emoji/speech_balloon.png 0 → 100755

2.08 KB

app/assets/images/emoji/speedboat.png 0 → 100755

3.43 KB

app/assets/images/emoji/squirrel.png 0 → 100755

9.13 KB

app/assets/images/emoji/star.png 0 → 100755

3.54 KB

app/assets/images/emoji/star2.png 0 → 100755

3.97 KB

app/assets/images/emoji/stars.png 0 → 100755

4.26 KB

app/assets/images/emoji/station.png 0 → 100755

4.72 KB

app/assets/images/emoji/statue_of_liberty.png 0 → 100755

5.93 KB

app/assets/images/emoji/steam_locomotive.png 0 → 100755

5.04 KB

app/assets/images/emoji/stew.png 0 → 100755

5.24 KB

app/assets/images/emoji/straight_ruler.png 0 → 100755

3.74 KB

app/assets/images/emoji/strawberry.png 0 → 100755

5.35 KB

app/assets/images/emoji/sun_with_face.png 0 → 100755

7.77 KB

app/assets/images/emoji/sunflower.png 0 → 100755

6.41 KB

app/assets/images/emoji/sunglasses.png 0 → 100755

5.61 KB

app/assets/images/emoji/sunny.png 0 → 100755

3.71 KB

app/assets/images/emoji/sunrise.png 0 → 100755

3.82 KB

app/assets/images/emoji/sunrise_over_mountains.png 0 → 100755

6.44 KB

app/assets/images/emoji/surfer.png 0 → 100755

6.11 KB

app/assets/images/emoji/sushi.png 0 → 100755

5.13 KB

app/assets/images/emoji/suspect.png 0 → 100755

1016 Bytes

app/assets/images/emoji/suspension_railway.png 0 → 100755

3.84 KB

app/assets/images/emoji/sweat.png 0 → 100755

5.45 KB

app/assets/images/emoji/sweat_drops.png 0 → 100755

4.67 KB

app/assets/images/emoji/sweat_smile.png 0 → 100755

6.37 KB

app/assets/images/emoji/sweet_potato.png 0 → 100755

5.55 KB

app/assets/images/emoji/swimmer.png 0 → 100755

4.28 KB

app/assets/images/emoji/symbols.png 0 → 100755

5.31 KB

app/assets/images/emoji/syringe.png 0 → 100755

2.97 KB

app/assets/images/emoji/tada.png 0 → 100755

5.81 KB

app/assets/images/emoji/tanabata_tree.png 0 → 100755

4.31 KB

app/assets/images/emoji/tangerine.png 0 → 100755

6.49 KB

app/assets/images/emoji/taurus.png 0 → 100755

4.62 KB

app/assets/images/emoji/taxi.png 0 → 100755

3.66 KB

app/assets/images/emoji/tea.png 0 → 100755

5.81 KB

app/assets/images/emoji/telephone.png 0 → 100755

5.37 KB

app/assets/images/emoji/telephone_receiver.png 0 → 100755

1.95 KB

app/assets/images/emoji/telescope.png 0 → 100755

3.24 KB

app/assets/images/emoji/tennis.png 0 → 100755

5.84 KB

app/assets/images/emoji/tent.png 0 → 100755

4.38 KB

app/assets/images/emoji/thought_balloon.png 0 → 100755

2.52 KB

app/assets/images/emoji/three.png 0 → 100755

3.67 KB

app/assets/images/emoji/thumbsdown.png 0 → 100755

4.95 KB

app/assets/images/emoji/thumbsup.png 0 → 100755

4.96 KB

app/assets/images/emoji/ticket.png 0 → 100755

3.02 KB

app/assets/images/emoji/tiger.png 0 → 100755

5.91 KB

app/assets/images/emoji/tiger2.png 0 → 100755

5.61 KB

app/assets/images/emoji/tired_face.png 0 → 100755

6.03 KB

app/assets/images/emoji/tm.png 0 → 100755

842 Bytes

app/assets/images/emoji/toilet.png 0 → 100755

1.69 KB

app/assets/images/emoji/tokyo_tower.png 0 → 100755

4.69 KB

app/assets/images/emoji/tomato.png 0 → 100755

5.61 KB

app/assets/images/emoji/tongue.png 0 → 100755

5.65 KB

app/assets/images/emoji/tongue2.png 0 → 100755

3.58 KB

app/assets/images/emoji/top.png 0 → 100755

3.7 KB

app/assets/images/emoji/tophat.png 0 → 100755

2.94 KB

app/assets/images/emoji/tractor.png 0 → 100755

5.54 KB

app/assets/images/emoji/traffic_light.png 0 → 100755

3.46 KB

app/assets/images/emoji/train.png 0 → 100755

3.81 KB

app/assets/images/emoji/train2.png 0 → 100755

4.7 KB

app/assets/images/emoji/tram.png 0 → 100755

4.75 KB

app/assets/images/emoji/triangular_flag_on_post.png 0 → 100755

1.37 KB

app/assets/images/emoji/triangular_ruler.png 0 → 100755

2.64 KB

app/assets/images/emoji/trident.png 0 → 100755

4.72 KB

app/assets/images/emoji/triumph.png 0 → 100755

6.02 KB

app/assets/images/emoji/trolleybus.png 0 → 100755

4.33 KB

app/assets/images/emoji/trollface.png 0 → 100755

4.79 KB

app/assets/images/emoji/trophy.png 0 → 100755

5.39 KB

app/assets/images/emoji/tropical_drink.png 0 → 100755

4.09 KB

app/assets/images/emoji/tropical_fish.png 0 → 100755

5.71 KB

app/assets/images/emoji/truck.png 0 → 100755

3.63 KB

app/assets/images/emoji/trumpet.png 0 → 100755

4.27 KB

app/assets/images/emoji/tshirt.png 0 → 100755

4.57 KB

app/assets/images/emoji/tulip.png 0 → 100755

5.92 KB

app/assets/images/emoji/turtle.png 0 → 100755

5.21 KB

app/assets/images/emoji/tv.png 0 → 100755

5.12 KB

app/assets/images/emoji/twisted_rightwards_arrows.png 0 → 100755

4.21 KB

app/assets/images/emoji/two.png 0 → 100755

3.44 KB

app/assets/images/emoji/two_hearts.png 0 → 100755

3.48 KB

app/assets/images/emoji/two_men_holding_hands.png 0 → 100755

6.83 KB

app/assets/images/emoji/two_women_holding_hands.png 0 → 100755

7.45 KB

app/assets/images/emoji/u5272.png 0 → 100755

4.43 KB

app/assets/images/emoji/u5408.png 0 → 100755

3.8 KB

app/assets/images/emoji/u55b6.png 0 → 100755

3.33 KB

app/assets/images/emoji/u6307.png 0 → 100755

4.01 KB

app/assets/images/emoji/u6708.png 0 → 100755

2.94 KB

app/assets/images/emoji/u6709.png 0 → 100755

3.12 KB

app/assets/images/emoji/u6e80.png 0 → 100755

4.32 KB

app/assets/images/emoji/u7121.png 0 → 100755

3.85 KB

app/assets/images/emoji/u7533.png 0 → 100755

2.98 KB

app/assets/images/emoji/u7981.png 0 → 100755

5.05 KB

app/assets/images/emoji/u7a7a.png 0 → 100755

4.08 KB

app/assets/images/emoji/uk.png 0 → 100755

5.76 KB

app/assets/images/emoji/umbrella.png 0 → 100755

4.63 KB

app/assets/images/emoji/unamused.png 0 → 100755

5.19 KB

app/assets/images/emoji/underage.png 0 → 100755

5.59 KB

app/assets/images/emoji/unlock.png 0 → 100755

3.47 KB

app/assets/images/emoji/up.png 0 → 100755

3.63 KB

app/assets/images/emoji/us.png 0 → 100755

6.14 KB

app/assets/images/emoji/v.png 0 → 100755

4.56 KB

app/assets/images/emoji/vertical_traffic_light.png 0 → 100755

3.34 KB

app/assets/images/emoji/vhs.png 0 → 100755

3.07 KB

app/assets/images/emoji/vibration_mode.png 0 → 100755

3.81 KB

app/assets/images/emoji/video_camera.png 0 → 100755

4.97 KB

app/assets/images/emoji/video_game.png 0 → 100755

4.84 KB

app/assets/images/emoji/violin.png 0 → 100755

4.9 KB

app/assets/images/emoji/virgo.png 0 → 100755

4.75 KB

app/assets/images/emoji/volcano.png 0 → 100755

6.02 KB

app/assets/images/emoji/vs.png 0 → 100755

3.34 KB

app/assets/images/emoji/walking.png 0 → 100755

2.41 KB

app/assets/images/emoji/waning_crescent_moon.png 0 → 100755

5.75 KB

app/assets/images/emoji/waning_gibbous_moon.png 0 → 100755

6.36 KB

app/assets/images/emoji/warning.png 0 → 100755

3.1 KB

app/assets/images/emoji/watch.png 0 → 100755

5.07 KB

app/assets/images/emoji/water_buffalo.png 0 → 100755

4.66 KB

app/assets/images/emoji/watermelon.png 0 → 100755

5.37 KB

app/assets/images/emoji/wave.png 0 → 100755

4.93 KB

app/assets/images/emoji/wavy_dash.png 0 → 100755

872 Bytes

app/assets/images/emoji/waxing_crescent_moon.png 0 → 100755

6.05 KB

app/assets/images/emoji/waxing_gibbous_moon.png 0 → 100755

6.3 KB

app/assets/images/emoji/wc.png 0 → 100755

3.99 KB

app/assets/images/emoji/weary.png 0 → 100755

6.13 KB

app/assets/images/emoji/wedding.png 0 → 100755

5.71 KB

app/assets/images/emoji/whale.png 0 → 100755

4.82 KB

app/assets/images/emoji/whale2.png 0 → 100755

5.89 KB

app/assets/images/emoji/wheelchair.png 0 → 100755

4.13 KB

app/assets/images/emoji/white_circle.png 0 → 100755

2.45 KB

app/assets/images/emoji/white_flower.png 0 → 100755

4.29 KB

app/assets/images/emoji/white_square.png 0 → 100755

1.38 KB

app/assets/images/emoji/wind_chime.png 0 → 100755

3.41 KB

app/assets/images/emoji/wine_glass.png 0 → 100755

3.08 KB

app/assets/images/emoji/wink.png 0 → 100755

5.13 KB

app/assets/images/emoji/wink2.png 0 → 100755

5.87 KB

app/assets/images/emoji/wolf.png 0 → 100755

4.73 KB

app/assets/images/emoji/woman.png 0 → 100755

6.73 KB

app/assets/images/emoji/womans_clothes.png 0 → 100755

3.98 KB

app/assets/images/emoji/womans_hat.png 0 → 100755

7.91 KB

app/assets/images/emoji/womens.png 0 → 100755

3.8 KB

app/assets/images/emoji/wrench.png 0 → 100755

2.71 KB

app/assets/images/emoji/x.png 0 → 100755

2 KB

app/assets/images/emoji/yellow_heart.png 0 → 100755

4.31 KB

app/assets/images/emoji/yen.png 0 → 100755

4.87 KB

app/assets/images/emoji/yum.png 0 → 100755

5.75 KB

app/assets/images/emoji/zap.png 0 → 100755

2.18 KB

app/assets/images/emoji/zero.png 0 → 100755

3.51 KB

app/assets/images/emoji/zzz.png 0 → 100755

1.98 KB

app/assets/javascripts/admin.js
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -$(document).ready(function(){  
2 - $('input#user_force_random_password').on('change', function(elem) {  
3 - var elems = $('#user_password, #user_password_confirmation');  
4 -  
5 - if ($(this).attr('checked')) {  
6 - elems.val('').attr('disabled', true);  
7 - } else {  
8 - elems.removeAttr('disabled');  
9 - }  
10 - });  
11 -});  
app/assets/javascripts/admin.js.coffee 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +$ ->
  2 + $('input#user_force_random_password').on 'change', (elem) ->
  3 + elems = $('#user_password, #user_password_confirmation')
  4 +
  5 + if $(@).attr 'checked'
  6 + elems.val('').attr 'disabled', true
  7 + else
  8 + elems.removeAttr 'disabled'
app/assets/javascripts/application.js
@@ -17,134 +17,3 @@ @@ -17,134 +17,3 @@
17 //= require raphael 17 //= require raphael
18 //= require branch-graph 18 //= require branch-graph
19 //= require_tree . 19 //= require_tree .
20 -  
21 -$(document).ready(function(){  
22 -  
23 - $(".one_click_select").live("click", function(){  
24 - $(this).select();  
25 - });  
26 -  
27 - $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){  
28 - var buttons = $('[type="submit"]', this);  
29 - switch( e.type ){  
30 - case 'ajax:beforeSend':  
31 - case 'submit':  
32 - buttons.attr('disabled', 'disabled');  
33 - break;  
34 - case ' ajax:complete':  
35 - default:  
36 - buttons.removeAttr('disabled');  
37 - break;  
38 - }  
39 - })  
40 -  
41 - $(".account-box").mouseenter(showMenu);  
42 - $(".account-box").mouseleave(resetMenu);  
43 -  
44 - $("#projects-list .project").live('click', function(e){  
45 - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {  
46 - location.href = $(this).attr("url");  
47 - e.stopPropagation();  
48 - return false;  
49 - }  
50 - });  
51 -  
52 - /**  
53 - * Focus search field by pressing 's' key  
54 - */  
55 - $(document).keypress(function(e) {  
56 - if( $(e.target).is(":input") ) return;  
57 - switch(e.which) {  
58 - case 115: focusSearch();  
59 - e.preventDefault();  
60 - }  
61 - });  
62 -  
63 - /**  
64 - * Commit show suppressed diff  
65 - *  
66 - */  
67 - $(".supp_diff_link").bind("click", function() {  
68 - showDiff(this);  
69 - });  
70 -  
71 - /**  
72 - * Note markdown preview  
73 - *  
74 - */  
75 - $(document).on('click', '#preview-link', function(e) {  
76 - $('#preview-note').text('Loading...');  
77 -  
78 - var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');  
79 - $(this).text(previewLinkText);  
80 -  
81 - var note = $('#note_note').val();  
82 - if (note.trim().length === 0) { note = 'Nothing to preview'; }  
83 - $.post($(this).attr('href'), {note: note}, function(data) {  
84 - $('#preview-note').html(data);  
85 - });  
86 -  
87 - $('#preview-note, #note_note').toggle();  
88 - e.preventDefault();  
89 - });  
90 -});  
91 -  
92 -function focusSearch() {  
93 - $("#search").focus();  
94 -}  
95 -  
96 -function updatePage(data){  
97 - $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});  
98 -}  
99 -  
100 -function showMenu() {  
101 - $(this).toggleClass('hover');  
102 -}  
103 -  
104 -function resetMenu() {  
105 - $(this).removeClass("hover");  
106 -}  
107 -  
108 -function slugify(text) {  
109 - return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();  
110 -}  
111 -  
112 -function showDiff(link) {  
113 - $(link).next('table').show();  
114 - $(link).remove();  
115 -}  
116 -  
117 -(function($){  
118 - var _chosen = $.fn.chosen;  
119 - $.fn.extend({  
120 - chosen: function(options) {  
121 - var default_options = {'search_contains' : 'true'};  
122 - $.extend(default_options, options);  
123 - return _chosen.apply(this, [default_options]);  
124 - }})  
125 -})(jQuery);  
126 -  
127 -  
128 -function ajaxGet(url) {  
129 - $.ajax({type: "GET", url: url, dataType: "script"});  
130 -}  
131 -  
132 -/**  
133 - * Disable button if text field is empty  
134 - */  
135 -function disableButtonIfEmtpyField(field_selector, button_selector) {  
136 - field = $(field_selector);  
137 - if(field.val() == "") {  
138 - field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled");  
139 - }  
140 -  
141 - field.on('keyup', function(){  
142 - var field = $(this);  
143 - var closest_submit = field.closest("form").find(button_selector);  
144 - if(field.val() == "") {  
145 - closest_submit.attr("disabled", "disabled").addClass("disabled");  
146 - } else {  
147 - closest_submit.removeAttr("disabled").removeClass("disabled");  
148 - }  
149 - })  
150 -}  
app/assets/javascripts/graph.js
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -function initGraphNav() {  
2 - $(".graph svg").css("position", "relative");  
3 - $("body").bind("keyup", function(e) {  
4 - if(e.keyCode == 37) { // left  
5 - $(".graph svg").animate({ left: "+=400" });  
6 - } else if(e.keyCode == 39) { // right  
7 - $(".graph svg").animate({ left: "-=400" });  
8 - }  
9 - });  
10 -}  
app/assets/javascripts/graph.js.coffee 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +initGraphNav = ->
  2 + $('.graph svg').css 'position', 'relative'
  3 +
  4 + $('body').bind 'keyup', (e) ->
  5 + if e.keyCode is 37 # left
  6 + $('.graph svg').animate left: '+=400'
  7 + else if e.keyCode is 39 # right
  8 + $('.graph svg').animate left: '-=400'
  9 +
  10 +window.initGraphNav = initGraphNav
app/assets/javascripts/issues.js
@@ -80,6 +80,10 @@ function issuesPage(){ @@ -80,6 +80,10 @@ function issuesPage(){
80 $(this).closest("form").submit(); 80 $(this).closest("form").submit();
81 }); 81 });
82 82
  83 + $("#new_issue_link").click(function(){
  84 + updateNewIssueURL();
  85 + });
  86 +
83 $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){ 87 $('body').on('ajax:success', '.close_issue, .reopen_issue, #new_issue', function(){
84 var t = $(this), 88 var t = $(this),
85 totalIssues, 89 totalIssues,
@@ -126,3 +130,20 @@ function issuesCheckChanged() { @@ -126,3 +130,20 @@ function issuesCheckChanged() {
126 $('.issues_filters').show(); 130 $('.issues_filters').show();
127 } 131 }
128 } 132 }
  133 +
  134 +function updateNewIssueURL(){
  135 + var new_issue_link = $("#new_issue_link");
  136 + var milestone_id = $("#milestone_id").val();
  137 + var assignee_id = $("#assignee_id").val();
  138 + var new_href = "";
  139 + if(milestone_id){
  140 + new_href = "issue[milestone_id]=" + milestone_id + "&";
  141 + }
  142 + if(assignee_id){
  143 + new_href = new_href + "issue[assignee_id]=" + assignee_id;
  144 + }
  145 + if(new_href.length){
  146 + new_href = new_issue_link.attr("href") + "?" + new_href;
  147 + new_issue_link.attr("href", new_href);
  148 + }
  149 +};
app/assets/javascripts/loader.js
@@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
1 -var Loader = {  
2 - img_src: "/assets/ajax-loader.gif",  
3 -  
4 - html:  
5 - function(width) {  
6 - img = $("<img>");  
7 - img.attr("width", width);  
8 - img.attr("src", this.img_src);  
9 - return img;  
10 - }  
11 -}  
app/assets/javascripts/loader.js.coffee 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +Loader =
  2 + html: (width) ->
  3 + $('<img>').attr src: '/assets/ajax-loader.gif', width: width
  4 +
  5 +window.Loader = Loader
app/assets/javascripts/main.js 0 → 100644
@@ -0,0 +1,130 @@ @@ -0,0 +1,130 @@
  1 +$(document).ready(function(){
  2 +
  3 + $(".one_click_select").live("click", function(){
  4 + $(this).select();
  5 + });
  6 +
  7 + $('body').on('ajax:complete, ajax:beforeSend, submit', 'form', function(e){
  8 + var buttons = $('[type="submit"]', this);
  9 + switch( e.type ){
  10 + case 'ajax:beforeSend':
  11 + case 'submit':
  12 + buttons.attr('disabled', 'disabled');
  13 + break;
  14 + case ' ajax:complete':
  15 + default:
  16 + buttons.removeAttr('disabled');
  17 + break;
  18 + }
  19 + })
  20 +
  21 + $(".account-box").mouseenter(showMenu);
  22 + $(".account-box").mouseleave(resetMenu);
  23 +
  24 + $("#projects-list .project").live('click', function(e){
  25 + if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {
  26 + location.href = $(this).attr("url");
  27 + e.stopPropagation();
  28 + return false;
  29 + }
  30 + });
  31 +
  32 + /**
  33 + * Focus search field by pressing 's' key
  34 + */
  35 + $(document).keypress(function(e) {
  36 + if( $(e.target).is(":input") ) return;
  37 + switch(e.which) {
  38 + case 115: focusSearch();
  39 + e.preventDefault();
  40 + }
  41 + });
  42 +
  43 + /**
  44 + * Commit show suppressed diff
  45 + *
  46 + */
  47 + $(".supp_diff_link").bind("click", function() {
  48 + showDiff(this);
  49 + });
  50 +
  51 + /**
  52 + * Note markdown preview
  53 + *
  54 + */
  55 + $(document).on('click', '#preview-link', function(e) {
  56 + $('#preview-note').text('Loading...');
  57 +
  58 + var previewLinkText = ($(this).text() == 'Preview' ? 'Edit' : 'Preview');
  59 + $(this).text(previewLinkText);
  60 +
  61 + var note = $('#note_note').val();
  62 + if (note.trim().length === 0) { note = 'Nothing to preview'; }
  63 + $.post($(this).attr('href'), {note: note}, function(data) {
  64 + $('#preview-note').html(data);
  65 + });
  66 +
  67 + $('#preview-note, #note_note').toggle();
  68 + e.preventDefault();
  69 + });
  70 +});
  71 +
  72 +function focusSearch() {
  73 + $("#search").focus();
  74 +}
  75 +
  76 +function updatePage(data){
  77 + $.ajax({type: "GET", url: location.href, data: data, dataType: "script"});
  78 +}
  79 +
  80 +function showMenu() {
  81 + $(this).toggleClass('hover');
  82 +}
  83 +
  84 +function resetMenu() {
  85 + $(this).removeClass("hover");
  86 +}
  87 +
  88 +function slugify(text) {
  89 + return text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase();
  90 +}
  91 +
  92 +function showDiff(link) {
  93 + $(link).next('table').show();
  94 + $(link).remove();
  95 +}
  96 +
  97 +(function($){
  98 + var _chosen = $.fn.chosen;
  99 + $.fn.extend({
  100 + chosen: function(options) {
  101 + var default_options = {'search_contains' : 'true'};
  102 + $.extend(default_options, options);
  103 + return _chosen.apply(this, [default_options]);
  104 + }})
  105 +})(jQuery);
  106 +
  107 +
  108 +function ajaxGet(url) {
  109 + $.ajax({type: "GET", url: url, dataType: "script"});
  110 +}
  111 +
  112 +/**
  113 + * Disable button if text field is empty
  114 + */
  115 +function disableButtonIfEmtpyField(field_selector, button_selector) {
  116 + field = $(field_selector);
  117 + if(field.val() == "") {
  118 + field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled");
  119 + }
  120 +
  121 + field.on('keyup', function(){
  122 + var field = $(this);
  123 + var closest_submit = field.closest("form").find(button_selector);
  124 + if(field.val() == "") {
  125 + closest_submit.attr("disabled", "disabled").addClass("disabled");
  126 + } else {
  127 + closest_submit.removeAttr("disabled").removeClass("disabled");
  128 + }
  129 + })
  130 +}
app/assets/javascripts/projects.js.coffee
1 window.Projects = -> 1 window.Projects = ->
2 - $("#project_name").live "change", ->  
3 - slug = slugify($(this).val())  
4 - $("#project_code").val(slug)  
5 - $("#project_path").val(slug) 2 + $('#project_name').on 'change', ->
  3 + slug = slugify $(@).val()
  4 + $('#project_code, #project_path').val slug
6 5
7 - $(".new_project, .edit_project").live "ajax:before", ->  
8 - $(".project_new_holder, .project_edit_holder").hide()  
9 - $(".save-project-loader").show() 6 + $('.new_project, .edit_project').on 'ajax:before', ->
  7 + $('.project_new_holder, .project_edit_holder').hide()
  8 + $('.save-project-loader').show()
10 9
11 - $("form #project_default_branch").chosen()  
12 - disableButtonIfEmtpyField "#project_name", ".project-submit" 10 + $('form #project_default_branch').chosen()
  11 + disableButtonIfEmtpyField '#project_name', '.project-submit'
13 12
14 # Git clone panel switcher 13 # Git clone panel switcher
15 $ -> 14 $ ->
16 - scope = $('.project_clone_holder') 15 + scope = $ '.project_clone_holder'
17 if scope.length > 0 16 if scope.length > 0
18 $('a, button', scope).click -> 17 $('a, button', scope).click ->
19 - $('a, button', scope).removeClass('active')  
20 - $(this).addClass('active')  
21 - $('#project_clone', scope).val($(this).data('clone')) 18 + $('a, button', scope).removeClass 'active'
  19 + $(@).addClass 'active'
  20 + $('#project_clone', scope).val $(@).data 'clone'
app/assets/javascripts/snippets.js
@@ -1,9 +0,0 @@ @@ -1,9 +0,0 @@
1 -$(document).ready(function(){  
2 - $("#snippets-table .snippet").live('click', function(e){  
3 - if(e.target.nodeName != "A" && e.target.nodeName != "INPUT") {  
4 - location.href = $(this).attr("url");  
5 - e.stopPropagation();  
6 - return false;  
7 - }  
8 - });  
9 -});  
app/assets/javascripts/snippets.js.coffee 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +$ ->
  2 + $('#snippets-table .snippet').live 'click', (e) ->
  3 + if e.target.nodeName isnt 'A' and e.target.nodeName isnt 'INPUT'
  4 + location.href = $(@).attr 'url'
  5 + e.stopPropagation()
  6 + false
app/assets/javascripts/team.js
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -function backToMembers(){  
2 - $("#new_team_member").hide("slide", { direction: "right" }, 150, function(){  
3 - $("#team-table").show("slide", { direction: "left" }, 150, function() {  
4 - $("#new_team_member").remove();  
5 - $(".add_new").show();  
6 - });  
7 - });  
8 -}  
app/assets/stylesheets/main.scss
1 @import "bootstrap"; 1 @import "bootstrap";
2 @import "bootstrap-responsive"; 2 @import "bootstrap-responsive";
3 3
4 -/** GITLAB colors **/ 4 +/** GitLab colors **/
5 $link_color:#3A89A3; 5 $link_color:#3A89A3;
6 $blue_link: #2fa0bb; 6 $blue_link: #2fa0bb;
7 $style_color: #474d57; 7 $style_color: #474d57;
8 $hover: #fdf5d9; 8 $hover: #fdf5d9;
9 9
10 -/** GITLAB Fonts **/ 10 +/** GitLab Fonts **/
11 @font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); } 11 @font-face { font-family: Korolev; src: url('korolev-medium-compressed.otf'); }
12 12
13 /** MIXINS **/ 13 /** MIXINS **/
@@ -113,9 +113,9 @@ $hover: #fdf5d9; @@ -113,9 +113,9 @@ $hover: #fdf5d9;
113 @import "themes/ui_modern.scss"; 113 @import "themes/ui_modern.scss";
114 114
115 /** 115 /**
116 - * Gitlab bootstrap. 116 + * GitLab bootstrap.
117 * Overrides some styles of twitter bootstrap. 117 * Overrides some styles of twitter bootstrap.
118 - * Also give some common classes for gitlab app 118 + * Also give some common classes for GitLab app
119 */ 119 */
120 @import "gitlab_bootstrap/common.scss"; 120 @import "gitlab_bootstrap/common.scss";
121 @import "gitlab_bootstrap/typography.scss"; 121 @import "gitlab_bootstrap/typography.scss";
app/controllers/application_controller.rb
@@ -11,15 +11,11 @@ class ApplicationController &lt; ActionController::Base @@ -11,15 +11,11 @@ class ApplicationController &lt; ActionController::Base
11 helper_method :abilities, :can? 11 helper_method :abilities, :can?
12 12
13 rescue_from Gitlab::Gitolite::AccessDenied do |exception| 13 rescue_from Gitlab::Gitolite::AccessDenied do |exception|
14 - render "errors/gitolite", layout: "error"  
15 - end  
16 -  
17 - rescue_from Gitlab::Gitolite::InvalidKey do |exception|  
18 - render "errors/invalid_ssh_key", layout: "error" 14 + render "errors/gitolite", layout: "error", status: 500
19 end 15 end
20 16
21 rescue_from Encoding::CompatibilityError do |exception| 17 rescue_from Encoding::CompatibilityError do |exception|
22 - render "errors/encoding", layout: "error", status: 404 18 + render "errors/encoding", layout: "error", status: 500
23 end 19 end
24 20
25 rescue_from ActiveRecord::RecordNotFound do |exception| 21 rescue_from ActiveRecord::RecordNotFound do |exception|
app/controllers/commits_controller.rb
@@ -64,19 +64,14 @@ class CommitsController &lt; ApplicationController @@ -64,19 +64,14 @@ class CommitsController &lt; ApplicationController
64 @commit.to_patch, 64 @commit.to_patch,
65 type: "text/plain", 65 type: "text/plain",
66 disposition: 'attachment', 66 disposition: 'attachment',
67 - filename: (@commit.id.to_s + ".patch") 67 + filename: "#{@commit.id.patch}"
68 ) 68 )
69 end 69 end
70 70
71 protected 71 protected
72 72
73 def load_refs 73 def load_refs
74 - if params[:ref].blank?  
75 - @branch = params[:branch].blank? ? nil : params[:branch]  
76 - @tag = params[:tag].blank? ? nil : params[:tag]  
77 - @ref = @branch || @tag || @project.try(:default_branch) || 'master'  
78 - else  
79 - @ref = params[:ref]  
80 - end 74 + @ref ||= params[:ref].presence || params[:branch].presence || params[:tag].presence
  75 + @ref ||= @ref || @project.try(:default_branch) || 'master'
81 end 76 end
82 end 77 end
app/controllers/issues_controller.rb
@@ -37,7 +37,7 @@ class IssuesController &lt; ApplicationController @@ -37,7 +37,7 @@ class IssuesController &lt; ApplicationController
37 end 37 end
38 38
39 def new 39 def new
40 - @issue = @project.issues.new 40 + @issue = @project.issues.new(params[:issue])
41 respond_with(@issue) 41 respond_with(@issue)
42 end 42 end
43 43
app/controllers/team_members_controller.rb
@@ -17,13 +17,12 @@ class TeamMembersController &lt; ApplicationController @@ -17,13 +17,12 @@ class TeamMembersController &lt; ApplicationController
17 end 17 end
18 18
19 def create 19 def create
20 - @team_member = UsersProject.new(params[:team_member])  
21 - @team_member.project = project  
22 - if @team_member.save  
23 - redirect_to team_project_path(@project)  
24 - else  
25 - render "new"  
26 - end 20 + @project.add_users_ids_to_team(
  21 + params[:user_ids],
  22 + params[:project_access]
  23 + )
  24 +
  25 + redirect_to team_project_path(@project)
27 end 26 end
28 27
29 def update 28 def update
app/helpers/gitlab_markdown_helper.rb
1 module GitlabMarkdownHelper 1 module GitlabMarkdownHelper
2 - # Replaces references (i.e. @abc, #123, !456, ...) in the text with links to  
3 - # the appropriate items in Gitlab.  
4 - #  
5 - # text - the source text  
6 - # html_options - extra options for the reference links as given to link_to  
7 - #  
8 - # note: reference links will only be generated if @project is set  
9 - #  
10 - # see Gitlab::Markdown for details on the supported syntax  
11 - def gfm(text, html_options = {})  
12 - return text if text.nil?  
13 - return text if @project.nil?  
14 -  
15 - # Extract pre blocks so they are not altered  
16 - # from http://github.github.com/github-flavored-markdown/  
17 - extractions = {}  
18 - text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|  
19 - md5 = Digest::MD5.hexdigest(match)  
20 - extractions[md5] = match  
21 - "{gfm-extraction-#{md5}}"  
22 - end  
23 -  
24 - # TODO: add popups with additional information  
25 -  
26 - parser = Gitlab::Markdown.new(@project, html_options)  
27 - text = parser.parse(text)  
28 -  
29 - # Insert pre block extractions  
30 - text.gsub!(/\{gfm-extraction-(\h{32})\}/) do  
31 - extractions[$1]  
32 - end  
33 -  
34 - sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class )  
35 - end 2 + include Gitlab::Markdown
36 3
37 # Use this in places where you would normally use link_to(gfm(...), ...). 4 # Use this in places where you would normally use link_to(gfm(...), ...).
38 # 5 #
@@ -60,7 +27,7 @@ module GitlabMarkdownHelper @@ -60,7 +27,7 @@ module GitlabMarkdownHelper
60 filter_html: true, 27 filter_html: true,
61 with_toc_data: true, 28 with_toc_data: true,
62 hard_wrap: true) 29 hard_wrap: true)
63 - @markdown ||= Redcarpet::Markdown.new(gitlab_renderer, 30 + @markdown = Redcarpet::Markdown.new(gitlab_renderer,
64 # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use 31 # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
65 no_intra_emphasis: true, 32 no_intra_emphasis: true,
66 tables: true, 33 tables: true,
app/helpers/projects_helper.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +module ProjectsHelper
  2 + def grouper_project_members(project)
  3 + @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access)
  4 + end
  5 +end
  6 +
app/mailers/notify.rb
@@ -111,18 +111,18 @@ class Notify &lt; ActionMailer::Base @@ -111,18 +111,18 @@ class Notify &lt; ActionMailer::Base
111 # Examples 111 # Examples
112 # 112 #
113 # >> subject('Lorem ipsum') 113 # >> subject('Lorem ipsum')
114 - # => "gitlab | Lorem ipsum" 114 + # => "GitLab | Lorem ipsum"
115 # 115 #
116 # # Automatically inserts Project name when @project is set 116 # # Automatically inserts Project name when @project is set
117 # >> @project = Project.last 117 # >> @project = Project.last
118 # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> 118 # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
119 # >> subject('Lorem ipsum') 119 # >> subject('Lorem ipsum')
120 - # => "gitlab | Lorem ipsum | Ruby on Rails" 120 + # => "GitLab | Lorem ipsum | Ruby on Rails"
121 # 121 #
122 # # Accepts multiple arguments 122 # # Accepts multiple arguments
123 # >> subject('Lorem ipsum', 'Dolor sit amet') 123 # >> subject('Lorem ipsum', 'Dolor sit amet')
124 - # => "gitlab | Lorem ipsum | Dolor sit amet" 124 + # => "GitLab | Lorem ipsum | Dolor sit amet"
125 def subject(*extra) 125 def subject(*extra)
126 - "gitlab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") 126 + "GitLab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "")
127 end 127 end
128 end 128 end
app/models/note.rb
@@ -103,7 +103,7 @@ class Note &lt; ActiveRecord::Base @@ -103,7 +103,7 @@ class Note &lt; ActiveRecord::Base
103 # Returns true if this is an upvote note, 103 # Returns true if this is an upvote note,
104 # otherwise false is returned 104 # otherwise false is returned
105 def upvote? 105 def upvote?
106 - note =~ /^\+1/ ? true : false 106 + note.start_with?('+1') || note.start_with?(':+1:')
107 end 107 end
108 end 108 end
109 # == Schema Information 109 # == Schema Information
app/models/users_project.rb
@@ -14,7 +14,7 @@ class UsersProject &lt; ActiveRecord::Base @@ -14,7 +14,7 @@ class UsersProject &lt; ActiveRecord::Base
14 after_save :update_repository 14 after_save :update_repository
15 after_destroy :update_repository 15 after_destroy :update_repository
16 16
17 - validates_uniqueness_of :user_id, scope: [:project_id] 17 + validates_uniqueness_of :user_id, scope: [:project_id], message: "already exists in project"
18 validates_presence_of :user_id 18 validates_presence_of :user_id
19 validates_presence_of :project_id 19 validates_presence_of :project_id
20 20
@@ -65,10 +65,10 @@ class UsersProject &lt; ActiveRecord::Base @@ -65,10 +65,10 @@ class UsersProject &lt; ActiveRecord::Base
65 65
66 def self.access_roles 66 def self.access_roles
67 { 67 {
68 - "Guest" => GUEST,  
69 - "Reporter" => REPORTER, 68 + "Guest" => GUEST,
  69 + "Reporter" => REPORTER,
70 "Developer" => DEVELOPER, 70 "Developer" => DEVELOPER,
71 - "Master" => MASTER 71 + "Master" => MASTER
72 } 72 }
73 end 73 end
74 74
app/views/errors/encoding.html.haml
1 -.alert-message.block-message.error  
2 - %h3 Encoding Error  
3 - %hr  
4 - %p  
5 - Page can't be loaded because of an encoding error. 1 +%h1 Encoding Error
  2 +%hr
  3 +%p Page can't be loaded because of an encoding error.
app/views/errors/gitolite.html.haml
1 %h1 Git Error 1 %h1 Git Error
2 %hr 2 %hr
3 -%h2 Gitlab was unable to access your Gitolite system. 3 +%h2 GitLab was unable to access your Gitolite system.
4 4
5 .git_error_tips 5 .git_error_tips
6 %h4 Tips for Administrator: 6 %h4 Tips for Administrator:
app/views/errors/invalid_ssh_key.html.haml
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -%h1 Git Error  
2 -%hr  
3 -%p Seems like SSH Key you provided is not a valid SSH key.  
app/views/help/index.html.haml
@@ -30,7 +30,7 @@ @@ -30,7 +30,7 @@
30 %h5= link_to "API", help_api_path 30 %h5= link_to "API", help_api_path
31 31
32 %li 32 %li
33 - %h5= link_to "Gitlab Markdown", help_markdown_path 33 + %h5= link_to "GitLab Markdown", help_markdown_path
34 34
35 %li 35 %li
36 %h5= link_to "SSH keys", help_ssh_path 36 %h5= link_to "SSH keys", help_ssh_path
app/views/help/markdown.html.haml
1 -%h3.page_title Gitlab Flavored Markdown 1 +%h3.page_title GitLab Flavored Markdown
2 .back_link 2 .back_link
3 = link_to help_path do 3 = link_to help_path do
4 &larr; to index 4 &larr; to index
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 .row 7 .row
8 .span8 8 .span8
9 %p 9 %p
10 - For Gitlab we developed something we call "Gitlab Flavored Markdown" (GFM). 10 + For GitLab we developed something we call "GitLab Flavored Markdown" (GFM).
11 It extends the standard Markdown in a few significant ways adds some useful functionality. 11 It extends the standard Markdown in a few significant ways adds some useful functionality.
12 12
13 %p You can use GFM in: 13 %p You can use GFM in:
@@ -20,6 +20,15 @@ @@ -20,6 +20,15 @@
20 %li milestones 20 %li milestones
21 %li wiki pages 21 %li wiki pages
22 22
  23 + .span4
  24 + .alert.alert-info
  25 + %p
  26 + If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent
  27 + %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax"
  28 + at Daring Fireball.
  29 +
  30 +.row
  31 + .span8
23 %h3 Differences from traditional Markdown 32 %h3 Differences from traditional Markdown
24 33
25 %h4 Newlines 34 %h4 Newlines
@@ -62,7 +71,30 @@ @@ -62,7 +71,30 @@
62 %p becomes 71 %p becomes
63 = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```} 72 = markdown %Q{```ruby\nrequire 'redcarpet'\nmarkdown = Redcarpet.new("Hello World!")\nputs markdown.to_html\n```}
64 73
65 - %h4 Special Gitlab references 74 + %h4 Emoji
  75 +
  76 +.row
  77 + .span8
  78 + :ruby
  79 + puts markdown %Q{Sometimes you want to be :cool: and add some :sparkles: to your :speech_balloon:. Well we have a :gift: for you:
  80 +
  81 + :exclamation: You can use emoji anywhere GFM is supported. :sunglasses:
  82 +
  83 + You can use it to point out a :bug: or warn about :monkey:patches. And if someone improves your really :snail: code, send them a :bouquet: or some :candy:. People will :heart: you for that.
  84 +
  85 + If you are :new: to this, don't be :fearful:. You can easily join the emoji :circus_tent:. All you need to do is to :book: up on the supported codes.
  86 + }
  87 +
  88 + .span4
  89 + .alert.alert-info
  90 + %p
  91 + Consult the
  92 + %strong= link_to "Emoji Cheat Sheet", "http://www.emoji-cheat-sheet.com/"
  93 + for a list of all supported emoji codes.
  94 +
  95 +.row
  96 + .span8
  97 + %h4 Special GitLab references
66 98
67 %p 99 %p
68 GFM recognizes special references. 100 GFM recognizes special references.
@@ -88,18 +120,10 @@ @@ -88,18 +120,10 @@
88 for commits 120 for commits
89 121
90 -# this example will only be shown if the user has a project with at least one issue 122 -# this example will only be shown if the user has a project with at least one issue
91 - - if project = current_user.projects.first  
92 - - if issue = project.issues.first  
93 - %p For example in your #{link_to project.name, project_path(project)} project something like 123 + - if @project = current_user.projects.first
  124 + - if issue = @project.issues.first
  125 + %p For example in your #{link_to @project.name, project_path(@project)} project, writing:
94 %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." 126 %pre= "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
95 - %p becomes 127 + %p becomes:
96 = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it." 128 = markdown "This is related to ##{issue.id}. @#{current_user.name} is working on solving it."
97 -  
98 -  
99 -  
100 - .span4.right  
101 - .alert.alert-info  
102 - %p  
103 - If you're not already familiar with Markdown, you should spend 15 minutes and go over the excellent  
104 - %strong= link_to "Markdown Syntax Guide", "http://daringfireball.net/projects/markdown/syntax"  
105 - at Daring Fireball. 129 + - @project = nil # Prevent this from bubbling up to page title
app/views/help/ssh.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 %hr 5 %hr
6 6
7 %p.slead 7 %p.slead
8 - SSH key allows you to establish a secure connection between your computer and Gitlab 8 + SSH key allows you to establish a secure connection between your computer and GitLab
9 9
10 %p.slead 10 %p.slead
11 To generate a new SSH key just open your terminal and use code below. 11 To generate a new SSH key just open your terminal and use code below.
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 \# Generating public/private rsa key pair... 17 \# Generating public/private rsa key pair...
18 18
19 %p.slead 19 %p.slead
20 - Next just use code below to dump your public key and add to GITLAB SSH Keys 20 + Next just use code below to dump your public key and add to GitLab SSH Keys
21 21
22 %pre.dark 22 %pre.dark
23 cat ~/.ssh/id_rsa.pub 23 cat ~/.ssh/id_rsa.pub
app/views/help/system_hooks.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 %hr 5 %hr
6 6
7 %p.slead 7 %p.slead
8 - Your Gitlab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member. 8 + Your GitLab instance can perform HTTP POST request on next event: create_project, delete_project, create_user, delete_user, change_team_member.
9 %br 9 %br
10 System Hooks can be used for logging or change information in LDAP server. 10 System Hooks can be used for logging or change information in LDAP server.
11 %br 11 %br
app/views/help/web_hooks.html.haml
@@ -5,11 +5,11 @@ @@ -5,11 +5,11 @@
5 %hr 5 %hr
6 6
7 %p.slead 7 %p.slead
8 - Every Gitlab project can trigger a web server whenever the repo is pushed to. 8 + Every GitLab project can trigger a web server whenever the repo is pushed to.
9 %br 9 %br
10 Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server. 10 Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
11 %br 11 %br
12 - GITLAB will send POST request with commits information on every push. 12 + GitLab will send POST request with commits information on every push.
13 %h5 Hooks request example: 13 %h5 Hooks request example:
14 = render "hooks/data_ex" 14 = render "hooks/data_ex"
15 15
app/views/help/workflow.html.haml
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 git commit -am "My feature is ready" 24 git commit -am "My feature is ready"
25 25
26 %li 26 %li
27 - %p Push your branch to gitlabhq 27 + %p Push your branch to GitLab
28 .bash 28 .bash
29 %pre.dark 29 %pre.dark
30 git push origin $feature_name 30 git push origin $feature_name
app/views/hooks/_data_ex.html.erb
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 :timestamp => "2012-01-03T23:36:29+02:00", 32 :timestamp => "2012-01-03T23:36:29+02:00",
33 :url => "http://localhost/diaspora/commits/da1560886d...", 33 :url => "http://localhost/diaspora/commits/da1560886d...",
34 :author => { 34 :author => {
35 - :name => "gitlab dev user", 35 + :name => "GitLab dev user",
36 :email => "gitlabdev@dv6700.(none)" 36 :email => "gitlabdev@dv6700.(none)"
37 } 37 }
38 } 38 }
app/views/issues/_form.html.haml
@@ -38,7 +38,7 @@ @@ -38,7 +38,7 @@
38 = f.label :description, "Details" 38 = f.label :description, "Details"
39 .input 39 .input
40 = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14 40 = f.text_area :description, maxlength: 2000, class: "xxlarge", rows: 14
41 - %p.hint Issues are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. 41 + %p.hint Issues are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
42 42
43 43
44 .actions 44 .actions
app/views/issues/index.html.haml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 .right 6 .right
7 .span5 7 .span5
8 - if can? current_user, :write_issue, @project 8 - if can? current_user, :write_issue, @project
9 - = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true do 9 + = link_to new_project_issue_path(@project), class: "right btn", title: "New Issue", remote: true, id: "new_issue_link" do
10 %i.icon-plus 10 %i.icon-plus
11 New Issue 11 New Issue
12 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do 12 = form_tag search_project_issues_path(@project), method: :get, remote: true, id: "issue_search_form", class: :right do
app/views/keys/index.html.haml
@@ -3,8 +3,8 @@ @@ -3,8 +3,8 @@
3 = link_to "Add new", new_key_path, class: "btn right" 3 = link_to "Add new", new_key_path, class: "btn right"
4 4
5 %hr 5 %hr
6 -%p.slead  
7 - SSH key allows you to establish a secure connection between your computer and Gitlab 6 +%p.slead
  7 + SSH key allows you to establish a secure connection between your computer and GitLab
8 8
9 9
10 %table#keys-table 10 %table#keys-table
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 %th 15 %th
16 - @keys.each do |key| 16 - @keys.each do |key|
17 = render(partial: 'show', locals: {key: key}) 17 = render(partial: 'show', locals: {key: key})
18 - - if @keys.blank? 18 + - if @keys.blank?
19 %tr 19 %tr
20 %td{colspan: 3} 20 %td{colspan: 3}
21 %h3.nothing_here_message There are no SSH keys with access to your account. 21 %h3.nothing_here_message There are no SSH keys with access to your account.
app/views/layouts/notify.html.haml
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 %head 2 %head
3 %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"} 3 %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
4 %title 4 %title
5 - gitlabhq 5 + GitLab
6 :css 6 :css
7 .header h1 {color: #BBBBBB !important; font: bold 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;} 7 .header h1 {color: #BBBBBB !important; font: bold 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;}
8 .header p {color: #c6c6c6; font: normal 12px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 18px;} 8 .header p {color: #c6c6c6; font: normal 12px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 18px;}
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 21
22 %td{align: "left", style: "padding: 18px 0 10px;", width: "580"} 22 %td{align: "left", style: "padding: 18px 0 10px;", width: "580"}
23 %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"} 23 %h1{style: "color: #BBBBBB; font: normal 32px Helvetica, Arial, sans-serif; margin: 0; padding: 0; line-height: 40px;"}
24 - gitlab 24 + GITLAB
25 - if @project 25 - if @project
26 | #{@project.name} 26 | #{@project.name}
27 %table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"} 27 %table{align: "center", bgcolor: "#fff", border: "0", cellpadding: "0", cellspacing: "0", style: "font-family: Helvetica, Arial, sans-serif; background: #fff;", width: "600"}
app/views/milestones/_form.html.haml
@@ -22,7 +22,7 @@ @@ -22,7 +22,7 @@
22 = f.label :description, "Description", class: "control-label" 22 = f.label :description, "Description", class: "control-label"
23 .controls 23 .controls
24 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10 24 = f.text_area :description, maxlength: 2000, class: "input-xlarge", rows: 10
25 - %p.hint Milestones are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. 25 + %p.hint Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
26 .span6 26 .span6
27 .control-group 27 .control-group
28 = f.label :due_date, "Due Date", class: "control-label" 28 = f.label :due_date, "Due Date", class: "control-label"
app/views/notes/_form.html.haml
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 = f.text_area :note, size: 255, class: 'note-text' 11 = f.text_area :note, size: 255, class: 'note-text'
12 #preview-note.preview_note.hide 12 #preview-note.preview_note.hide
13 .hint 13 .hint
14 - .right Comments are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. 14 + .right Comments are parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
15 .clearfix 15 .clearfix
16 16
17 .row.note_advanced_opts.hide 17 .row.note_advanced_opts.hide
app/views/notify/new_user_email.html.haml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "} 6 %h2{style: "color:#646464; font-weight: bold; margin: 0; padding: 0; line-height: 26px; font-size: 18px; font-family: Helvetica, Arial, sans-serif; "}
7 Hi #{@user['name']}! 7 Hi #{@user['name']}!
8 %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "} 8 %p{style: "color:#767676; font-weight: normal; margin: 0; padding: 0; line-height: 20px; font-size: 12px;font-family: Helvetica, Arial, sans-serif; "}
9 - Administrator created account for you. Now you are a member of company gitlab application. 9 + Administrator created account for you. Now you are a member of company GitLab application.
10 %td{style: "font-size: 1px; line-height: 1px;", width: "21"} 10 %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
11 %tr 11 %tr
12 %td{style: "font-size: 1px; line-height: 1px;", width: "21"} 12 %td{style: "font-size: 1px; line-height: 1px;", width: "21"}
app/views/projects/_team.html.haml
1 -%table  
2 - %thead  
3 - %tr  
4 - %th User  
5 - %th Permissions  
6 - %tbody  
7 - - @project.users_projects.each do |up|  
8 - = render(partial: 'team_members/show', locals: {member: up}) 1 +- grouper_project_members(@project).each do |access, members|
  2 + %table
  3 + %thead
  4 + %tr
  5 + %th.span7
  6 + = Project.access_options.key(access).pluralize
  7 + %th
  8 + %tbody
  9 + - members.each do |up|
  10 + = render(partial: 'team_members/show', locals: {member: up})
9 11
10 12
11 :javascript 13 :javascript
app/views/team_members/_form.html.haml
1 -%h3= "New Team member" 1 +%h3.page_title
  2 + = "New Team member(s)"
2 %hr 3 %hr
3 = form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f| 4 = form_for @team_member, as: :team_member, url: project_team_members_path(@project, @team_member) do |f|
4 -if @team_member.errors.any? 5 -if @team_member.errors.any?
@@ -7,27 +8,23 @@ @@ -7,27 +8,23 @@
7 - @team_member.errors.full_messages.each do |msg| 8 - @team_member.errors.full_messages.each do |msg|
8 %li= msg 9 %li= msg
9 10
  11 + %h6 1. Choose people you want in the team
10 .clearfix 12 .clearfix
11 - = f.label :user_id, "Name"  
12 - .input= f.select(:user_id, User.not_in_project(@project).all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, { style: "width:300px" }) 13 + = f.label :user_ids, "Peolpe"
  14 + .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), { class: "xxlarge", multiple: true })
13 15
14 16
  17 + %h6 2. Set access level for them
15 .clearfix 18 .clearfix
16 = f.label :project_access, "Project Access" 19 = f.label :project_access, "Project Access"
17 - .input= f.select :project_access, options_for_select(Project.access_options, @team_member.project_access), {}, class: "project-access-select" 20 + .input= select_tag :project_access, options_for_select(Project.access_options, @team_member.project_access), class: "project-access-select"
18 21
19 22
20 .actions 23 .actions
21 - = f.submit 'Save', class: "btn primary"  
22 - = link_to "Cancel", team_project_path(@project), class: "btn" 24 + = f.submit 'Save', class: "btn save-btn"
  25 + = link_to "Cancel", team_project_path(@project), class: "btn cancel-btn"
23 26
24 -:css  
25 - form select {  
26 - width:300px;  
27 - }  
28 27
29 :javascript 28 :javascript
30 - $('select#team_member_user_id').chosen();  
31 - $('select#team_member_project_access').chosen();  
32 - //$('select#team_member_repo_access').chosen();  
33 - //$('select#team_member_project_access').chosen(); 29 + $('select#user_ids').chosen();
  30 + $('select#project_access').chosen();
app/views/team_members/_show.html.haml
@@ -2,12 +2,6 @@ @@ -2,12 +2,6 @@
2 - allow_admin = can? current_user, :admin_project, @project 2 - allow_admin = can? current_user, :admin_project, @project
3 %tr{id: dom_id(member), class: "team_member_row user_#{user.id}"} 3 %tr{id: dom_id(member), class: "team_member_row user_#{user.id}"}
4 %td 4 %td
5 - .right  
6 - - if @project.owner == user  
7 - %span.label Project Owner  
8 - - if user.blocked  
9 - %span.label Blocked  
10 -  
11 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do 5 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
12 = image_tag gravatar_icon(user.email, 40), class: "avatar s32" 6 = image_tag gravatar_icon(user.email, 40), class: "avatar s32"
13 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do 7 = link_to project_team_member_path(@project, member), title: user.name, class: "dark" do
@@ -16,5 +10,11 @@ @@ -16,5 +10,11 @@
16 %div.cgray= user.email 10 %div.cgray= user.email
17 11
18 %td 12 %td
19 - = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|  
20 - = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select", disabled: !allow_admin 13 + .right
  14 + - if @project.owner == user
  15 + %span.btn.disabled.success Project Owner
  16 + - if user.blocked
  17 + %span.btn.disabled.blocked Blocked
  18 + - if allow_admin
  19 + = form_for(member, as: :team_member, url: project_team_member_path(@project, member)) do |f|
  20 + = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select"
app/views/wikis/_form.html.haml
@@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
14 .middle_box_content 14 .middle_box_content
15 .input 15 .input
16 %span.cgray 16 %span.cgray
17 - Wiki content is parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. 17 + Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
18 To link to a (new) page you can just type 18 To link to a (new) page you can just type
19 %code [Link Title](page-slug) 19 %code [Link Title](page-slug)
20 \. 20 \.
doc/api/README.md
1 -# Gitlab API 1 +# GitLab API
2 2
3 All API requests require authentication. You need to pass a `private_token` parameter to authenticate. You can find or reset your private token in your profile. 3 All API requests require authentication. You need to pass a `private_token` parameter to authenticate. You can find or reset your private token in your profile.
4 4
@@ -10,7 +10,7 @@ If no, or an invalid, `private_token` is provided then an error message will be @@ -10,7 +10,7 @@ If no, or an invalid, `private_token` is provided then an error message will be
10 } 10 }
11 ``` 11 ```
12 12
13 -API requests should be prefixed with `api` and the API version. The API version is equal to the Gitlab major version number, which is defined in `lib/api.rb`. 13 +API requests should be prefixed with `api` and the API version. The API version is equal to the GitLab major version number, which is defined in `lib/api.rb`.
14 14
15 Example of a valid API request: 15 Example of a valid API request:
16 16
doc/api/projects.md
@@ -102,6 +102,12 @@ Parameters: @@ -102,6 +102,12 @@ Parameters:
102 + `name` (required) - new project name 102 + `name` (required) - new project name
103 + `code` (optional) - new project code, uses project name if not set 103 + `code` (optional) - new project code, uses project name if not set
104 + `path` (optional) - new project path, uses project name if not set 104 + `path` (optional) - new project path, uses project name if not set
  105 ++ `description (optional) - short project description
  106 ++ `default_branch` (optional) - 'master' by default
  107 ++ `issues_enabled` (optional) - enabled by default
  108 ++ `wall_enabled` (optional) - enabled by default
  109 ++ `merge_requests_enabled` (optional) - enabled by default
  110 ++ `wiki_enabled` (optional) - enabled by default
105 111
106 Will return created project with status `201 Created` on success, or `404 Not 112 Will return created project with status `201 Created` on success, or `404 Not
107 found` on fail. 113 found` on fail.
doc/installation.md
@@ -167,7 +167,7 @@ and ensure you have followed all of the above steps carefully. @@ -167,7 +167,7 @@ and ensure you have followed all of the above steps carefully.
167 # Login to MySQL 167 # Login to MySQL
168 $ mysql -u root -p 168 $ mysql -u root -p
169 169
170 - # Create the gitlabhq production database 170 + # Create the GitLab production database
171 mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; 171 mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
172 172
173 # Create the MySQL User change $password to a real password 173 # Create the MySQL User change $password to a real password
features/projects/issues/issues.feature
@@ -4,7 +4,7 @@ Feature: Issues @@ -4,7 +4,7 @@ Feature: Issues
4 And I own project "Shop" 4 And I own project "Shop"
5 And project "Shop" have "Release 0.4" open issue 5 And project "Shop" have "Release 0.4" open issue
6 And project "Shop" have "Release 0.3" closed issue 6 And project "Shop" have "Release 0.3" closed issue
7 - And I visit project "Shop" issues page 7 + And I visit project "Shop" issues page
8 8
9 Scenario: I should see open issues 9 Scenario: I should see open issues
10 Given I should see "Release 0.4" in issues 10 Given I should see "Release 0.4" in issues
@@ -36,3 +36,47 @@ Feature: Issues @@ -36,3 +36,47 @@ Feature: Issues
36 Given I visit issue page "Release 0.4" 36 Given I visit issue page "Release 0.4"
37 And I leave a comment like "XML attached" 37 And I leave a comment like "XML attached"
38 Then I should see comment "XML attached" 38 Then I should see comment "XML attached"
  39 +
  40 + @javascript
  41 + Scenario: I search issue
  42 + Given I fill in issue search with "Release"
  43 + Then I should see "Release 0.4" in issues
  44 + And I should not see "Release 0.3" in issues
  45 +
  46 + @javascript
  47 + Scenario: I search issue that not exist
  48 + Given I fill in issue search with "Bug"
  49 + Then I should not see "Release 0.4" in issues
  50 + And I should not see "Release 0.3" in issues
  51 +
  52 +
  53 + @javascript
  54 + Scenario: I search all issues
  55 + Given I click link "All"
  56 + And I fill in issue search with "0.3"
  57 + Then I should see "Release 0.3" in issues
  58 + And I should not see "Release 0.4" in issues
  59 +
  60 + @javascript
  61 + Scenario: I clear search
  62 + Given I click link "All"
  63 + And I fill in issue search with "Something"
  64 + And I fill in issue search with ""
  65 + Then I should see "Release 0.4" in issues
  66 + And I should see "Release 0.3" in issues
  67 +
  68 + @javascript
  69 + Scenario: I create Issue with pre-selected milestone
  70 + Given project "Shop" has milestone "v2.2"
  71 + And project "Shop" has milestone "v3.0"
  72 + And I visit project "Shop" issues page
  73 + When I select milestone "v3.0"
  74 + And I click link "New Issue"
  75 + Then I should see selected milestone with title "v3.0"
  76 +
  77 + @javascript
  78 + Scenario: I create Issue with pre-selected assignee
  79 + When I select first assignee from "Shop" project
  80 + And I click link "New Issue"
  81 + Then I should see first assignee from "Shop" as selected assignee
  82 +
features/step_definitions/common_steps.rb 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +include LoginHelpers
  2 +
  3 +Given /^I signin as a user$/ do
  4 + login_as :user
  5 +end
  6 +
  7 +When /^I click link "(.*?)"$/ do |link|
  8 + click_link link
  9 +end
  10 +
  11 +When /^I click button "(.*?)"$/ do |button|
  12 + click_button button
  13 +end
  14 +
  15 +When /^I fill in "(.*?)" with "(.*?)"$/ do |field, value|
  16 + fill_in field, :with => value
  17 +end
  18 +
  19 +Given /^show me page$/ do
  20 + save_and_open_page
  21 +end
features/step_definitions/dashboard_steps.rb
1 -Given /^I visit dashboard page$/ do  
2 - visit dashboard_path  
3 -end  
4 -  
5 Then /^I should see "(.*?)" link$/ do |arg1| 1 Then /^I should see "(.*?)" link$/ do |arg1|
6 page.should have_link(arg1) 2 page.should have_link(arg1)
7 end 3 end
@@ -51,10 +47,10 @@ Then /^I click &quot;(.*?)&quot; link$/ do |arg1| @@ -51,10 +47,10 @@ Then /^I click &quot;(.*?)&quot; link$/ do |arg1|
51 end 47 end
52 48
53 Then /^I see prefilled new Merge Request page$/ do 49 Then /^I see prefilled new Merge Request page$/ do
54 - current_path.should == new_project_merge_request_path(@project)  
55 - find("#merge_request_source_branch").value.should == "new_design"  
56 - find("#merge_request_target_branch").value.should == "master"  
57 - find("#merge_request_title").value.should == "New Design" 50 + current_path.should == new_project_merge_request_path(@project)
  51 + find("#merge_request_source_branch").value.should == "new_design"
  52 + find("#merge_request_target_branch").value.should == "master"
  53 + find("#merge_request_title").value.should == "New Design"
58 end 54 end
59 55
60 Given /^I visit dashboard search page$/ do 56 Given /^I visit dashboard search page$/ do
@@ -66,10 +62,6 @@ Given /^I search for &quot;(.*?)&quot;$/ do |arg1| @@ -66,10 +62,6 @@ Given /^I search for &quot;(.*?)&quot;$/ do |arg1|
66 click_button "Search" 62 click_button "Search"
67 end 63 end
68 64
69 -Given /^I visit dashboard issues page$/ do  
70 - visit dashboard_issues_path  
71 -end  
72 -  
73 Then /^I should see issues assigned to me$/ do 65 Then /^I should see issues assigned to me$/ do
74 issues = @user.issues 66 issues = @user.issues
75 issues.each do |issue| 67 issues.each do |issue|
@@ -78,10 +70,6 @@ Then /^I should see issues assigned to me$/ do @@ -78,10 +70,6 @@ Then /^I should see issues assigned to me$/ do
78 end 70 end
79 end 71 end
80 72
81 -Given /^I visit dashboard merge requests page$/ do  
82 - visit dashboard_merge_requests_path  
83 -end  
84 -  
85 Then /^I should see my merge requests$/ do 73 Then /^I should see my merge requests$/ do
86 merge_requests = @user.merge_requests 74 merge_requests = @user.merge_requests
87 merge_requests.each do |mr| 75 merge_requests.each do |mr|
features/step_definitions/profile/profile_steps.rb
1 -Given /^I visit profile page$/ do  
2 - visit profile_path  
3 -end  
4 -  
5 Then /^I should see my profile info$/ do 1 Then /^I should see my profile info$/ do
6 page.should have_content "Profile" 2 page.should have_content "Profile"
7 page.should have_content @user.name 3 page.should have_content @user.name
8 page.should have_content @user.email 4 page.should have_content @user.email
9 end 5 end
10 6
11 -Given /^I visit profile password page$/ do  
12 - visit profile_password_path  
13 -end  
14 -  
15 Then /^I change my password$/ do 7 Then /^I change my password$/ do
16 fill_in "user_password", :with => "222333" 8 fill_in "user_password", :with => "222333"
17 fill_in "user_password_confirmation", :with => "222333" 9 fill_in "user_password_confirmation", :with => "222333"
@@ -22,10 +14,6 @@ Then /^I should be redirected to sign in page$/ do @@ -22,10 +14,6 @@ Then /^I should be redirected to sign in page$/ do
22 current_path.should == new_user_session_path 14 current_path.should == new_user_session_path
23 end 15 end
24 16
25 -Given /^I visit profile token page$/ do  
26 - visit profile_token_path  
27 -end  
28 -  
29 Then /^I reset my token$/ do 17 Then /^I reset my token$/ do
30 @old_token = @user.private_token 18 @old_token = @user.private_token
31 click_button "Reset" 19 click_button "Reset"
features/step_definitions/project/browse_code_steps.rb
1 -Given /^I visit project source page$/ do  
2 - visit tree_project_ref_path(@project, @project.root_ref)  
3 -end  
4 -  
5 Then /^I should see files from repository$/ do 1 Then /^I should see files from repository$/ do
6 page.should have_content("app") 2 page.should have_content("app")
7 page.should have_content("History") 3 page.should have_content("History")
8 page.should have_content("Gemfile") 4 page.should have_content("Gemfile")
9 end 5 end
10 6
11 -Given /^I visit project source page for "(.*?)"$/ do |arg1|  
12 - visit tree_project_ref_path(@project, arg1)  
13 -end  
14 -  
15 Then /^I should see files from repository for "(.*?)"$/ do |arg1| 7 Then /^I should see files from repository for "(.*?)"$/ do |arg1|
16 current_path.should == tree_project_ref_path(@project, arg1) 8 current_path.should == tree_project_ref_path(@project, arg1)
17 page.should have_content("app") 9 page.should have_content("app")
@@ -31,10 +23,6 @@ Given /^I click on raw button$/ do @@ -31,10 +23,6 @@ Given /^I click on raw button$/ do
31 click_link "raw" 23 click_link "raw"
32 end 24 end
33 25
34 -Given /^I visit blob file from repo$/ do  
35 - visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH)  
36 -end  
37 -  
38 Then /^I should see raw file content$/ do 26 Then /^I should see raw file content$/ do
39 page.source.should == ValidCommit::BLOB_FILE 27 page.source.should == ValidCommit::BLOB_FILE
40 end 28 end
features/step_definitions/project/project_commits_steps.rb
1 -Given /^I visit project commits page$/ do  
2 - visit project_commits_path(@project)  
3 -end  
4 -  
5 Then /^I see project commits$/ do 1 Then /^I see project commits$/ do
6 current_path.should == project_commits_path(@project) 2 current_path.should == project_commits_path(@project)
7 3
@@ -23,19 +19,11 @@ Then /^I see commits atom feed$/ do @@ -23,19 +19,11 @@ Then /^I see commits atom feed$/ do
23 page.body.should have_selector("entry summary", :text => commit.description) 19 page.body.should have_selector("entry summary", :text => commit.description)
24 end 20 end
25 21
26 -Given /^I click on commit link$/ do  
27 - visit project_commit_path(@project, ValidCommit::ID)  
28 -end  
29 -  
30 Then /^I see commit info$/ do 22 Then /^I see commit info$/ do
31 page.should have_content ValidCommit::MESSAGE 23 page.should have_content ValidCommit::MESSAGE
32 page.should have_content "Showing 1 changed file" 24 page.should have_content "Showing 1 changed file"
33 end 25 end
34 26
35 -Given /^I visit compare refs page$/ do  
36 - visit compare_project_commits_path(@project)  
37 -end  
38 -  
39 Given /^I fill compare fields with refs$/ do 27 Given /^I fill compare fields with refs$/ do
40 fill_in "from", :with => "master" 28 fill_in "from", :with => "master"
41 fill_in "to", :with => "stable" 29 fill_in "to", :with => "stable"
@@ -48,18 +36,6 @@ Given /^I see compared refs$/ do @@ -48,18 +36,6 @@ Given /^I see compared refs$/ do
48 page.should have_content "Showing 73 changed files" 36 page.should have_content "Showing 73 changed files"
49 end 37 end
50 38
51 -Given /^I visit project branches page$/ do  
52 - visit branches_project_repository_path(@project)  
53 -end  
54 -  
55 -Given /^I visit project commit page$/ do  
56 - visit project_commit_path(@project, ValidCommit::ID)  
57 -end  
58 -  
59 -Given /^I visit project tags page$/ do  
60 - visit tags_project_repository_path(@project)  
61 -end  
62 -  
63 Then /^I should see "(.*?)" recent branches list$/ do |arg1| 39 Then /^I should see "(.*?)" recent branches list$/ do |arg1|
64 page.should have_content("Branches") 40 page.should have_content("Branches")
65 page.should have_content("master") 41 page.should have_content("master")
@@ -76,7 +52,7 @@ Then /^I should see &quot;(.*?)&quot; all tags list$/ do |arg1| @@ -76,7 +52,7 @@ Then /^I should see &quot;(.*?)&quot; all tags list$/ do |arg1|
76 end 52 end
77 53
78 Then /^I should see "(.*?)" protected branches list$/ do |arg1| 54 Then /^I should see "(.*?)" protected branches list$/ do |arg1|
79 - within "table" do 55 + within "table" do
80 page.should have_content "stable" 56 page.should have_content "stable"
81 page.should_not have_content "master" 57 page.should_not have_content "master"
82 end 58 end
features/step_definitions/project/project_issues_steps.rb
@@ -8,16 +8,12 @@ Given /^project &quot;(.*?)&quot; have &quot;(.*?)&quot; closed issue$/ do |arg1, arg2| @@ -8,16 +8,12 @@ Given /^project &quot;(.*?)&quot; have &quot;(.*?)&quot; closed issue$/ do |arg1, arg2|
8 Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true) 8 Factory.create(:issue, :title => arg2, :project => project, :author => project.users.first, :closed => true)
9 end 9 end
10 10
11 -Given /^I visit project "(.*?)" issues page$/ do |arg1|  
12 - visit project_issues_path(Project.find_by_name(arg1))  
13 -end  
14 -  
15 Given /^I should see "(.*?)" in issues$/ do |arg1| 11 Given /^I should see "(.*?)" in issues$/ do |arg1|
16 - page.should have_content arg1 12 + page.should have_content arg1
17 end 13 end
18 14
19 Given /^I should not see "(.*?)" in issues$/ do |arg1| 15 Given /^I should not see "(.*?)" in issues$/ do |arg1|
20 - page.should_not have_content arg1 16 + page.should_not have_content arg1
21 end 17 end
22 18
23 Then /^I should see issue "(.*?)"$/ do |arg1| 19 Then /^I should see issue "(.*?)"$/ do |arg1|
@@ -27,11 +23,6 @@ Then /^I should see issue &quot;(.*?)&quot;$/ do |arg1| @@ -27,11 +23,6 @@ Then /^I should see issue &quot;(.*?)&quot;$/ do |arg1|
27 page.should have_content issue.project.name 23 page.should have_content issue.project.name
28 end 24 end
29 25
30 -Given /^I visit issue page "(.*?)"$/ do |arg1|  
31 - issue = Issue.find_by_title(arg1)  
32 - visit project_issue_path(issue.project, issue)  
33 -end  
34 -  
35 Given /^I submit new issue "(.*?)"$/ do |arg1| 26 Given /^I submit new issue "(.*?)"$/ do |arg1|
36 fill_in "issue_title", with: arg1 27 fill_in "issue_title", with: arg1
37 click_button "Submit new issue" 28 click_button "Submit new issue"
@@ -51,7 +42,40 @@ Given /^I visit project &quot;(.*?)&quot; labels page$/ do |arg1| @@ -51,7 +42,40 @@ Given /^I visit project &quot;(.*?)&quot; labels page$/ do |arg1|
51 end 42 end
52 43
53 Then /^I should see label "(.*?)"$/ do |arg1| 44 Then /^I should see label "(.*?)"$/ do |arg1|
54 - within ".labels-table" do 45 + within ".labels-table" do
55 page.should have_content arg1 46 page.should have_content arg1
56 end 47 end
57 end 48 end
  49 +
  50 +Given /^I fill in issue search with "(.*?)"$/ do |arg1|
  51 + # Because fill_in, with: "" triggers nothing
  52 + # we need to trigger a keyup event
  53 + if arg1 == ''
  54 + page.execute_script("$('.issue_search').val('').keyup();");
  55 + end
  56 + fill_in 'issue_search', with: arg1
  57 +end
  58 +
  59 +When /^I select milestone "(.*?)"$/ do |milestone_title|
  60 + select milestone_title, from: "milestone_id"
  61 +end
  62 +
  63 +Then /^I should see selected milestone with title "(.*?)"$/ do |milestone_title|
  64 + issues_milestone_selector = "#issue_milestone_id_chzn/a"
  65 + wait_until{ page.has_content?("Details") }
  66 + page.find(issues_milestone_selector).should have_content(milestone_title)
  67 +end
  68 +
  69 +When /^I select first assignee from "(.*?)" project$/ do |project_name|
  70 + project = Project.find_by_name project_name
  71 + first_assignee = project.users.first
  72 + select first_assignee.name, from: "assignee_id"
  73 +end
  74 +
  75 +Then /^I should see first assignee from "(.*?)" as selected assignee$/ do |project_name|
  76 + issues_assignee_selector = "#issue_assignee_id_chzn/a"
  77 + wait_until{ page.has_content?("Details") }
  78 + project = Project.find_by_name project_name
  79 + assignee_name = project.users.first.name
  80 + page.find(issues_assignee_selector).should have_content(assignee_name)
  81 +end
features/step_definitions/project/project_merge_requests_steps.rb
@@ -8,21 +8,17 @@ Given /^project &quot;(.*?)&quot; have &quot;(.*?)&quot; closed merge request$/ do |arg1, arg2| @@ -8,21 +8,17 @@ Given /^project &quot;(.*?)&quot; have &quot;(.*?)&quot; closed merge request$/ do |arg1, arg2|
8 Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first, :closed => true) 8 Factory.create(:merge_request, :title => arg2, :project => project, :author => project.users.first, :closed => true)
9 end 9 end
10 10
11 -Given /^I visit project "(.*?)" merge requests page$/ do |arg1|  
12 - visit project_merge_requests_path(Project.find_by_name(arg1))  
13 -end  
14 -  
15 Then /^I should see "(.*?)" in merge requests$/ do |arg1| 11 Then /^I should see "(.*?)" in merge requests$/ do |arg1|
16 - page.should have_content arg1 12 + page.should have_content arg1
17 end 13 end
18 14
19 Then /^I should not see "(.*?)" in merge requests$/ do |arg1| 15 Then /^I should not see "(.*?)" in merge requests$/ do |arg1|
20 - page.should_not have_content arg1 16 + page.should_not have_content arg1
21 end 17 end
22 18
23 Then /^I should see merge request "(.*?)"$/ do |arg1| 19 Then /^I should see merge request "(.*?)"$/ do |arg1|
24 merge_request = MergeRequest.find_by_title(arg1) 20 merge_request = MergeRequest.find_by_title(arg1)
25 - page.should have_content(merge_request.title[0..10]) 21 + page.should have_content(merge_request.title[0..10])
26 page.should have_content(merge_request.target_branch) 22 page.should have_content(merge_request.target_branch)
27 page.should have_content(merge_request.source_branch) 23 page.should have_content(merge_request.source_branch)
28 end 24 end
@@ -34,11 +30,6 @@ Given /^I submit new merge request &quot;(.*?)&quot;$/ do |arg1| @@ -34,11 +30,6 @@ Given /^I submit new merge request &quot;(.*?)&quot;$/ do |arg1|
34 click_button "Save" 30 click_button "Save"
35 end 31 end
36 32
37 -Given /^I visit merge request page "(.*?)"$/ do |arg1|  
38 - mr = MergeRequest.find_by_title(arg1)  
39 - visit project_merge_request_path(mr.project, mr)  
40 -end  
41 -  
42 Then /^I should see closed merge request "(.*?)"$/ do |arg1| 33 Then /^I should see closed merge request "(.*?)"$/ do |arg1|
43 mr = MergeRequest.find_by_title(arg1) 34 mr = MergeRequest.find_by_title(arg1)
44 mr.closed.should be_true 35 mr.closed.should be_true
features/step_definitions/project/project_milestones_steps.rb
@@ -12,11 +12,6 @@ Given /^project &quot;(.*?)&quot; has milestone &quot;(.*?)&quot;$/ do |arg1, arg2| @@ -12,11 +12,6 @@ Given /^project &quot;(.*?)&quot; has milestone &quot;(.*?)&quot;$/ do |arg1, arg2|
12 end 12 end
13 end 13 end
14 14
15 -Given /^I visit project "(.*?)" milestones page$/ do |arg1|  
16 - @project = Project.find_by_name(arg1)  
17 - visit project_milestones_path(@project)  
18 -end  
19 -  
20 Then /^I should see active milestones$/ do 15 Then /^I should see active milestones$/ do
21 milestone = @project.milestones.first 16 milestone = @project.milestones.first
22 page.should have_content(milestone.title[0..10]) 17 page.should have_content(milestone.title[0..10])
features/step_definitions/project/project_team_steps.rb
@@ -8,10 +8,6 @@ Given /^&quot;(.*?)&quot; is &quot;(.*?)&quot; developer$/ do |arg1, arg2| @@ -8,10 +8,6 @@ Given /^&quot;(.*?)&quot; is &quot;(.*?)&quot; developer$/ do |arg1, arg2|
8 project.add_access(user, :write) 8 project.add_access(user, :write)
9 end 9 end
10 10
11 -Given /^I visit project "(.*?)" team page$/ do |arg1|  
12 - visit team_project_path(Project.find_by_name(arg1))  
13 -end  
14 -  
15 Then /^I should be able to see myself in team$/ do 11 Then /^I should be able to see myself in team$/ do
16 page.should have_content(@user.name) 12 page.should have_content(@user.name)
17 page.should have_content(@user.email) 13 page.should have_content(@user.email)
@@ -23,15 +19,11 @@ Then /^I should see &quot;(.*?)&quot; in team list$/ do |arg1| @@ -23,15 +19,11 @@ Then /^I should see &quot;(.*?)&quot; in team list$/ do |arg1|
23 page.should have_content(user.email) 19 page.should have_content(user.email)
24 end 20 end
25 21
26 -Given /^I click link "(.*?)"$/ do |arg1|  
27 - click_link arg1  
28 -end  
29 -  
30 Given /^I select "(.*?)" as "(.*?)"$/ do |arg1, arg2| 22 Given /^I select "(.*?)" as "(.*?)"$/ do |arg1, arg2|
31 user = User.find_by_name(arg1) 23 user = User.find_by_name(arg1)
32 - within "#new_team_member" do  
33 - select user.name, :from => "team_member_user_id"  
34 - select arg2, :from => "team_member_project_access" 24 + within "#new_team_member" do
  25 + select user.name, :from => "user_ids"
  26 + select arg2, :from => "project_access"
35 end 27 end
36 click_button "Save" 28 click_button "Save"
37 end 29 end
@@ -44,7 +36,7 @@ end @@ -44,7 +36,7 @@ end
44 36
45 Given /^I change "(.*?)" role to "(.*?)"$/ do |arg1, arg2| 37 Given /^I change "(.*?)" role to "(.*?)"$/ do |arg1, arg2|
46 user = User.find_by_name(arg1) 38 user = User.find_by_name(arg1)
47 - within ".user_#{user.id}" do 39 + within ".user_#{user.id}" do
48 select arg2, :from => "team_member_project_access" 40 select arg2, :from => "team_member_project_access"
49 end 41 end
50 end 42 end
features/step_definitions/project/project_wiki_steps.rb
1 -Given /^I visit project wiki page$/ do  
2 - visit project_wiki_path(@project, :index)  
3 -end  
4 -  
5 Given /^I create Wiki page$/ do 1 Given /^I create Wiki page$/ do
6 fill_in "Title", :with => 'Test title' 2 fill_in "Title", :with => 'Test title'
7 fill_in "Content", :with => '[link test](test)' 3 fill_in "Content", :with => '[link test](test)'
features/step_definitions/project/projects_steps.rb
1 -include LoginHelpers  
2 -  
3 -Given /^I signin as a user$/ do  
4 - login_as :user  
5 -end  
6 -  
7 When /^I visit new project page$/ do 1 When /^I visit new project page$/ do
8 visit new_project_path 2 visit new_project_path
9 end 3 end
@@ -65,10 +59,6 @@ Given /^I visit project &quot;(.*?)&quot; network page$/ do |arg1| @@ -65,10 +59,6 @@ Given /^I visit project &quot;(.*?)&quot; network page$/ do |arg1|
65 visit graph_project_path(project) 59 visit graph_project_path(project)
66 end 60 end
67 61
68 -Given /^show me page$/ do  
69 - save_and_open_page  
70 -end  
71 -  
72 Given /^page should have network graph$/ do 62 Given /^page should have network graph$/ do
73 page.should have_content "Project Network Graph" 63 page.should have_content "Project Network Graph"
74 within ".graph" do 64 within ".graph" do
features/step_definitions/visit_steps.rb 0 → 100644
@@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
  1 +Given /^I visit project "(.*?)" issues page$/ do |arg1|
  2 + visit project_issues_path(Project.find_by_name(arg1))
  3 +end
  4 +
  5 +Given /^I visit issue page "(.*?)"$/ do |arg1|
  6 + issue = Issue.find_by_title(arg1)
  7 + visit project_issue_path(issue.project, issue)
  8 +end
  9 +
  10 +Given /^I visit project "(.*?)" merge requests page$/ do |arg1|
  11 + visit project_merge_requests_path(Project.find_by_name(arg1))
  12 +end
  13 +
  14 +Given /^I visit merge request page "(.*?)"$/ do |arg1|
  15 + mr = MergeRequest.find_by_title(arg1)
  16 + visit project_merge_request_path(mr.project, mr)
  17 +end
  18 +
  19 +Given /^I visit project "(.*?)" milestones page$/ do |arg1|
  20 + @project = Project.find_by_name(arg1)
  21 + visit project_milestones_path(@project)
  22 +end
  23 +
  24 +Given /^I visit project commits page$/ do
  25 + visit project_commits_path(@project)
  26 +end
  27 +
  28 +Given /^I visit compare refs page$/ do
  29 + visit compare_project_commits_path(@project)
  30 +end
  31 +
  32 +Given /^I visit project branches page$/ do
  33 + visit branches_project_repository_path(@project)
  34 +end
  35 +
  36 +Given /^I visit project commit page$/ do
  37 + visit project_commit_path(@project, ValidCommit::ID)
  38 +end
  39 +
  40 +Given /^I visit project tags page$/ do
  41 + visit tags_project_repository_path(@project)
  42 +end
  43 +
  44 +Given /^I click on commit link$/ do
  45 + visit project_commit_path(@project, ValidCommit::ID)
  46 +end
  47 +
  48 +Given /^I visit project source page$/ do
  49 + visit tree_project_ref_path(@project, @project.root_ref)
  50 +end
  51 +
  52 +Given /^I visit project source page for "(.*?)"$/ do |arg1|
  53 + visit tree_project_ref_path(@project, arg1)
  54 +end
  55 +
  56 +Given /^I visit blob file from repo$/ do
  57 + visit tree_project_ref_path(@project, ValidCommit::ID, :path => ValidCommit::BLOB_FILE_PATH)
  58 +end
  59 +
  60 +Given /^I visit project "(.*?)" team page$/ do |arg1|
  61 + visit team_project_path(Project.find_by_name(arg1))
  62 +end
  63 +
  64 +Given /^I visit project wiki page$/ do
  65 + visit project_wiki_path(@project, :index)
  66 +end
  67 +
  68 +Given /^I visit profile page$/ do
  69 + visit profile_path
  70 +end
  71 +
  72 +Given /^I visit profile token page$/ do
  73 + visit profile_token_path
  74 +end
  75 +
  76 +Given /^I visit profile password page$/ do
  77 + visit profile_password_path
  78 +end
  79 +
  80 +Given /^I visit dashboard page$/ do
  81 + visit dashboard_path
  82 +end
  83 +
  84 +Given /^I visit dashboard issues page$/ do
  85 + visit dashboard_issues_path
  86 +end
  87 +
  88 +Given /^I visit dashboard merge requests page$/ do
  89 + visit dashboard_merge_requests_path
  90 +end
  91 +
lib/api/projects.rb
@@ -29,14 +29,24 @@ module Gitlab @@ -29,14 +29,24 @@ module Gitlab
29 # name (required) - name for new project 29 # name (required) - name for new project
30 # code (optional) - code for new project, uses project name if not set 30 # code (optional) - code for new project, uses project name if not set
31 # path (optional) - path for new project, uses project name if not set 31 # path (optional) - path for new project, uses project name if not set
  32 + # description (optional) - short project description
  33 + # default_branch (optional) - 'master' by default
  34 + # issues_enabled (optional) - enabled by default
  35 + # wall_enabled (optional) - enabled by default
  36 + # merge_requests_enabled (optional) - enabled by default
  37 + # wiki_enabled (optional) - enabled by default
32 # Example Request 38 # Example Request
33 # POST /projects 39 # POST /projects
34 post do 40 post do
35 - project = {}  
36 - project[:name] = params[:name]  
37 - project[:code] = params[:code] || project[:name]  
38 - project[:path] = params[:path] || project[:name]  
39 - @project = Project.create_by_user(project, current_user) 41 + params[:code] ||= params[:name]
  42 + params[:path] ||= params[:name]
  43 + project_attrs = {}
  44 + params.each_pair do |k ,v|
  45 + if Project.attribute_names.include? k
  46 + project_attrs[k] = v
  47 + end
  48 + end
  49 + @project = Project.create_by_user(project_attrs, current_user)
40 if @project.saved? 50 if @project.saved?
41 present @project, with: Entities::Project 51 present @project, with: Entities::Project
42 else 52 else
lib/gitlab/backend/gitolite.rb
1 -require 'gitolite'  
2 -require 'timeout'  
3 -require 'fileutils' 1 +require_relative 'gitolite_config'
4 2
5 -# TODO: refactor & cleanup  
6 module Gitlab 3 module Gitlab
7 class Gitolite 4 class Gitolite
8 class AccessDenied < StandardError; end 5 class AccessDenied < StandardError; end
9 - class InvalidKey < StandardError; end 6 +
  7 + def config
  8 + Gitlab::GitoliteConfig.new
  9 + end
10 10
11 def set_key key_id, key_content, projects 11 def set_key key_id, key_content, projects
12 - configure do |c|  
13 - c.update_keys(key_id, key_content)  
14 - c.update_projects(projects) 12 + config.apply do |config|
  13 + config.write_key(key_id, key_content)
  14 + config.update_projects(projects)
15 end 15 end
16 end 16 end
17 17
18 def remove_key key_id, projects 18 def remove_key key_id, projects
19 - configure do |c|  
20 - c.delete_key(key_id)  
21 - c.update_projects(projects) 19 + config.apply do |config|
  20 + config.rm_key(key_id)
  21 + config.update_projects(projects)
22 end 22 end
23 end 23 end
24 24
25 def update_repository project 25 def update_repository project
26 - configure do |c|  
27 - c.update_project(project.path, project)  
28 - end 26 + config.update_project!(project.path, project)
29 end 27 end
30 28
31 - alias_method :create_repository, :update_repository  
32 -  
33 def remove_repository project 29 def remove_repository project
34 - configure do |c|  
35 - c.destroy_project(project)  
36 - end 30 + config.destroy_project!(project)
37 end 31 end
38 32
39 def url_to_repo path 33 def url_to_repo path
40 Gitlab.config.ssh_path + "#{path}.git" 34 Gitlab.config.ssh_path + "#{path}.git"
41 end 35 end
42 36
43 - def initialize  
44 - # create tmp dir  
45 - @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}")  
46 - end  
47 -  
48 def enable_automerge 37 def enable_automerge
49 - configure do |git|  
50 - git.admin_all_repo  
51 - end  
52 - end  
53 -  
54 - protected  
55 -  
56 - def destroy_project(project)  
57 - FileUtils.rm_rf(project.path_to_repo)  
58 -  
59 - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))  
60 - conf = ga_repo.config  
61 - conf.rm_repo(project.path)  
62 - ga_repo.save  
63 - end  
64 -  
65 - #update or create  
66 - def update_keys(user, key)  
67 - File.open(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"), 'w') {|f| f.write(key.gsub(/\n/,'')) }  
68 - end  
69 -  
70 - def delete_key(user)  
71 - File.unlink(File.join(@local_dir, 'gitolite/keydir',"#{user}.pub"))  
72 - `cd #{File.join(@local_dir,'gitolite')} ; git rm keydir/#{user}.pub`  
73 - end  
74 -  
75 - # update or create  
76 - def update_project(repo_name, project)  
77 - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))  
78 - conf = ga_repo.config  
79 - repo = update_project_config(project, conf)  
80 - conf.add_repo(repo, true)  
81 -  
82 - ga_repo.save  
83 - end  
84 -  
85 - # Updates many projects and uses project.path as the repo path  
86 - # An order of magnitude faster than update_project  
87 - def update_projects(projects)  
88 - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))  
89 - conf = ga_repo.config  
90 -  
91 - projects.each do |project|  
92 - repo = update_project_config(project, conf)  
93 - conf.add_repo(repo, true)  
94 - end  
95 -  
96 - ga_repo.save  
97 - end  
98 -  
99 - def update_project_config(project, conf)  
100 - repo_name = project.path  
101 -  
102 - repo = if conf.has_repo?(repo_name)  
103 - conf.get_repo(repo_name)  
104 - else  
105 - ::Gitolite::Config::Repo.new(repo_name)  
106 - end  
107 -  
108 - name_readers = project.repository_readers  
109 - name_writers = project.repository_writers  
110 - name_masters = project.repository_masters  
111 -  
112 - pr_br = project.protected_branches.map(&:name).join("$ ")  
113 -  
114 - repo.clean_permissions  
115 -  
116 - # Deny access to protected branches for writers  
117 - unless name_writers.blank? || pr_br.blank?  
118 - repo.add_permission("-", pr_br.strip + "$ ", name_writers)  
119 - end  
120 -  
121 - # Add read permissions  
122 - repo.add_permission("R", "", name_readers) unless name_readers.blank?  
123 -  
124 - # Add write permissions  
125 - repo.add_permission("RW+", "", name_writers) unless name_writers.blank?  
126 - repo.add_permission("RW+", "", name_masters) unless name_masters.blank?  
127 -  
128 - repo  
129 - end  
130 -  
131 - def admin_all_repo  
132 - ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))  
133 - conf = ga_repo.config  
134 - owner_name = ""  
135 -  
136 - # Read gitolite-admin user  
137 - #  
138 - begin  
139 - repo = conf.get_repo("gitolite-admin")  
140 - owner_name = repo.permissions[0]["RW+"][""][0]  
141 - raise StandardError if owner_name.blank?  
142 - rescue => ex  
143 - puts "Can't determine gitolite-admin owner".red  
144 - raise StandardError  
145 - end  
146 -  
147 - # @ALL repos premission for gitolite owner  
148 - repo_name = "@all"  
149 - repo = if conf.has_repo?(repo_name)  
150 - conf.get_repo(repo_name)  
151 - else  
152 - ::Gitolite::Config::Repo.new(repo_name)  
153 - end  
154 -  
155 - repo.add_permission("RW+", "", owner_name)  
156 - conf.add_repo(repo, true)  
157 - ga_repo.save 38 + config.admin_all_repo!(project)
158 end 39 end
159 40
160 - private  
161 -  
162 - def pull  
163 - # create tmp dir  
164 - @local_dir = File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}")  
165 - Dir.mkdir @local_dir  
166 -  
167 - `git clone #{Gitlab.config.gitolite_admin_uri} #{@local_dir}/gitolite`  
168 - end  
169 -  
170 - def push  
171 - Dir.chdir(File.join(@local_dir, "gitolite"))  
172 - `git add -A`  
173 - `git commit -am "Gitlab"`  
174 - `git push`  
175 - Dir.chdir(Rails.root)  
176 -  
177 - FileUtils.rm_rf(@local_dir)  
178 - end  
179 -  
180 - def configure  
181 - Timeout::timeout(30) do  
182 - File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f|  
183 - begin  
184 - f.flock(File::LOCK_EX)  
185 - pull  
186 - yield(self)  
187 - push  
188 - ensure  
189 - f.flock(File::LOCK_UN)  
190 - end  
191 - end  
192 - end  
193 - rescue Exception => ex  
194 - if ex.message =~ /is not a valid SSH key string/  
195 - raise Gitolite::InvalidKey.new("ssh key is not valid")  
196 - else  
197 - Gitlab::Logger.error(ex.message)  
198 - raise Gitolite::AccessDenied.new("gitolite timeout")  
199 - end  
200 - end 41 + alias_method :create_repository, :update_repository
201 end 42 end
202 end 43 end
lib/gitlab/backend/gitolite_config.rb 0 → 100644
@@ -0,0 +1,203 @@ @@ -0,0 +1,203 @@
  1 +require 'gitolite'
  2 +require 'timeout'
  3 +require 'fileutils'
  4 +
  5 +module Gitlab
  6 + class GitoliteConfig
  7 + class PullError < StandardError; end
  8 + class PushError < StandardError; end
  9 +
  10 + attr_reader :config_tmp_dir, :ga_repo, :conf
  11 +
  12 + def config_tmp_dir
  13 + @config_tmp_dir ||= File.join(Rails.root, 'tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
  14 + end
  15 +
  16 + def ga_repo
  17 + @ga_repo ||= ::Gitolite::GitoliteAdmin.new(File.join(config_tmp_dir,'gitolite'))
  18 + end
  19 +
  20 + def apply
  21 + Timeout::timeout(30) do
  22 + File.open(File.join(Rails.root, 'tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
  23 + begin
  24 + # Set exclusive lock
  25 + # to prevent race condition
  26 + f.flock(File::LOCK_EX)
  27 +
  28 + # Pull gitolite-admin repo
  29 + # in tmp dir before do any changes
  30 + pull(config_tmp_dir)
  31 +
  32 + # Build ga_repo object and @conf
  33 + # to access gitolite-admin configuration
  34 + @conf = ga_repo.config
  35 +
  36 + # Do any changes
  37 + # in gitolite-admin
  38 + # config here
  39 + yield(self)
  40 +
  41 + # Save changes in
  42 + # gitolite-admin repo
  43 + # before pusht it
  44 + ga_repo.save
  45 +
  46 + # Push gitolite-admin repo
  47 + # to apply all changes
  48 + push(config_tmp_dir)
  49 +
  50 + # Remove tmp dir
  51 + # wiith gitolite-admin
  52 + FileUtils.rm_rf(config_tmp_dir)
  53 + ensure
  54 + # unlock so other task cann access
  55 + # gitolite configuration
  56 + f.flock(File::LOCK_UN)
  57 + end
  58 + end
  59 + end
  60 + rescue PullError => ex
  61 + Gitlab::Logger.error("Pull error -> " + ex.message)
  62 + raise Gitolite::AccessDenied, ex.message
  63 +
  64 + rescue PushError => ex
  65 + Gitlab::Logger.error("Push error -> " + " " + ex.message)
  66 + raise Gitolite::AccessDenied, ex.message
  67 +
  68 + rescue Exception => ex
  69 + Gitlab::Logger.error(ex.class.name + " " + ex.message)
  70 + raise Gitolite::AccessDenied.new("gitolite timeout")
  71 + end
  72 +
  73 + def destroy_project(project)
  74 + FileUtils.rm_rf(project.path_to_repo)
  75 + conf.rm_repo(project.path)
  76 + end
  77 +
  78 + def destroy_project!(project)
  79 + apply do |config|
  80 + config.destroy_project(project)
  81 + end
  82 + end
  83 +
  84 + def write_key(id, key)
  85 + File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f|
  86 + f.write(key.gsub(/\n/,''))
  87 + end
  88 + end
  89 +
  90 + def rm_key(user)
  91 + File.unlink(File.join(config_tmp_dir, 'gitolite/keydir',"#{user}.pub"))
  92 + `cd #{File.join(config_tmp_dir,'gitolite')} ; git rm keydir/#{user}.pub`
  93 + end
  94 +
  95 + # update or create
  96 + def update_project(repo_name, project)
  97 + repo = update_project_config(project, conf)
  98 + conf.add_repo(repo, true)
  99 + end
  100 +
  101 + def update_project!(repo_name, project)
  102 + apply do |config|
  103 + config.update_project(repo_name, project)
  104 + end
  105 + end
  106 +
  107 + # Updates many projects and uses project.path as the repo path
  108 + # An order of magnitude faster than update_project
  109 + def update_projects(projects)
  110 + projects.each do |project|
  111 + repo = update_project_config(project, conf)
  112 + conf.add_repo(repo, true)
  113 + end
  114 + end
  115 +
  116 + def update_project_config(project, conf)
  117 + repo_name = project.path
  118 +
  119 + repo = if conf.has_repo?(repo_name)
  120 + conf.get_repo(repo_name)
  121 + else
  122 + ::Gitolite::Config::Repo.new(repo_name)
  123 + end
  124 +
  125 + name_readers = project.repository_readers
  126 + name_writers = project.repository_writers
  127 + name_masters = project.repository_masters
  128 +
  129 + pr_br = project.protected_branches.map(&:name).join("$ ")
  130 +
  131 + repo.clean_permissions
  132 +
  133 + # Deny access to protected branches for writers
  134 + unless name_writers.blank? || pr_br.blank?
  135 + repo.add_permission("-", pr_br.strip + "$ ", name_writers)
  136 + end
  137 +
  138 + # Add read permissions
  139 + repo.add_permission("R", "", name_readers) unless name_readers.blank?
  140 +
  141 + # Add write permissions
  142 + repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
  143 + repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
  144 +
  145 + repo
  146 + end
  147 +
  148 + # Enable access to all repos for gitolite admin.
  149 + # We use it for accept merge request feature
  150 + def admin_all_repo
  151 + owner_name = ""
  152 +
  153 + # Read gitolite-admin user
  154 + #
  155 + begin
  156 + repo = conf.get_repo("gitolite-admin")
  157 + owner_name = repo.permissions[0]["RW+"][""][0]
  158 + raise StandardError if owner_name.blank?
  159 + rescue => ex
  160 + puts "Can't determine gitolite-admin owner".red
  161 + raise StandardError
  162 + end
  163 +
  164 + # @ALL repos premission for gitolite owner
  165 + repo_name = "@all"
  166 + repo = if conf.has_repo?(repo_name)
  167 + conf.get_repo(repo_name)
  168 + else
  169 + ::Gitolite::Config::Repo.new(repo_name)
  170 + end
  171 +
  172 + repo.add_permission("RW+", "", owner_name)
  173 + conf.add_repo(repo, true)
  174 + end
  175 +
  176 + def admin_all_repo!
  177 + apply { |config| config.admin_all_repo }
  178 + end
  179 +
  180 + private
  181 +
  182 + def pull tmp_dir
  183 + Dir.mkdir tmp_dir
  184 + `git clone #{Gitlab.config.gitolite_admin_uri} #{tmp_dir}/gitolite`
  185 +
  186 + unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf'))
  187 + raise PullError, "unable to clone gitolite-admin repo"
  188 + end
  189 + end
  190 +
  191 + def push tmp_dir
  192 + Dir.chdir(File.join(tmp_dir, "gitolite"))
  193 + system('git add -A')
  194 + system('git commit -am "GitLab"')
  195 + if system('git push')
  196 + Dir.chdir(Rails.root)
  197 + else
  198 + raise PushError, "unable to push gitolite-admin repo"
  199 + end
  200 + end
  201 + end
  202 +end
  203 +
lib/gitlab/markdown.rb
1 module Gitlab 1 module Gitlab
2 - # Custom parser for Gitlab-flavored Markdown 2 + # Custom parser for GitLab-flavored Markdown
3 # 3 #
4 - # It replaces references in the text with links to the appropriate items in Gitlab. 4 + # It replaces references in the text with links to the appropriate items in
  5 + # GitLab.
5 # 6 #
6 # Supported reference formats are: 7 # Supported reference formats are:
7 # * @foo for team members 8 # * @foo for team members
@@ -10,19 +11,20 @@ module Gitlab @@ -10,19 +11,20 @@ module Gitlab
10 # * $123 for snippets 11 # * $123 for snippets
11 # * 123456 for commits 12 # * 123456 for commits
12 # 13 #
13 - # Examples 14 + # It also parses Emoji codes to insert images. See
  15 + # http://www.emoji-cheat-sheet.com/ for a list of the supported icons.
14 # 16 #
15 - # >> m = Markdown.new(...) 17 + # Examples
16 # 18 #
17 - # >> m.parse("Hey @david, can you fix this?") 19 + # >> gfm("Hey @david, can you fix this?")
18 # => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?" 20 # => "Hey <a href="/gitlab/team_members/1">@david</a>, can you fix this?"
19 # 21 #
20 - # >> m.parse("Commit 35d5f7c closes #1234") 22 + # >> gfm("Commit 35d5f7c closes #1234")
21 # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>" 23 # => "Commit <a href="/gitlab/commits/35d5f7c">35d5f7c</a> closes <a href="/gitlab/issues/1234">#1234</a>"
22 - class Markdown  
23 - include Rails.application.routes.url_helpers  
24 - include ActionView::Helpers  
25 - 24 + #
  25 + # >> gfm(":trollface:")
  26 + # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
  27 + module Markdown
26 REFERENCE_PATTERN = %r{ 28 REFERENCE_PATTERN = %r{
27 ([^\w&;])? # Prefix (1) 29 ([^\w&;])? # Prefix (1)
28 ( # Reference (2) 30 ( # Reference (2)
@@ -33,15 +35,57 @@ module Gitlab @@ -33,15 +35,57 @@ module Gitlab
33 ([^\w&;])? # Suffix (6) 35 ([^\w&;])? # Suffix (6)
34 }x.freeze 36 }x.freeze
35 37
  38 + EMOJI_PATTERN = %r{(:(\S+):)}.freeze
  39 +
36 attr_reader :html_options 40 attr_reader :html_options
37 41
38 - def initialize(project, html_options = {})  
39 - @project = project 42 + # Public: Parse the provided text with GitLab-Flavored Markdown
  43 + #
  44 + # text - the source text
  45 + # html_options - extra options for the reference links as given to link_to
  46 + #
  47 + # Note: reference links will only be generated if @project is set
  48 + def gfm(text, html_options = {})
  49 + return text if text.nil?
  50 +
  51 + # prevents the string supplied through the _text_ argument to be altered
  52 + text = text.dup
  53 +
40 @html_options = html_options 54 @html_options = html_options
  55 +
  56 + # Extract pre blocks so they are not altered
  57 + # from http://github.github.com/github-flavored-markdown/
  58 + extractions = {}
  59 + text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}m) do |match|
  60 + md5 = Digest::MD5.hexdigest(match)
  61 + extractions[md5] = match
  62 + "{gfm-extraction-#{md5}}"
  63 + end
  64 +
  65 + # TODO: add popups with additional information
  66 +
  67 + text = parse(text)
  68 +
  69 + # Insert pre block extractions
  70 + text.gsub!(/\{gfm-extraction-(\h{32})\}/) do
  71 + extractions[$1]
  72 + end
  73 +
  74 + sanitize text.html_safe, attributes: ActionView::Base.sanitized_allowed_attributes + %w(id class)
41 end 75 end
42 76
  77 + private
  78 +
  79 + # Private: Parses text for references and emoji
  80 + #
  81 + # text - Text to parse
  82 + #
  83 + # Note: reference links will only be generated if @project is set
  84 + #
  85 + # Returns parsed text
43 def parse(text) 86 def parse(text)
44 - text.gsub(REFERENCE_PATTERN) do |match| 87 + # parse reference links
  88 + text.gsub!(REFERENCE_PATTERN) do |match|
45 prefix = $1 || '' 89 prefix = $1 || ''
46 reference = $2 90 reference = $2
47 identifier = $3 || $4 || $5 91 identifier = $3 || $4 || $5
@@ -52,10 +96,28 @@ module Gitlab @@ -52,10 +96,28 @@ module Gitlab
52 else 96 else
53 match 97 match
54 end 98 end
  99 + end if @project
  100 +
  101 + # parse emoji
  102 + text.gsub!(EMOJI_PATTERN) do |match|
  103 + if valid_emoji?($2)
  104 + image_tag("emoji/#{$2}.png", size: "20x20", class: 'emoji', title: $1, alt: $1)
  105 + else
  106 + match
  107 + end
55 end 108 end
  109 +
  110 + text
56 end 111 end
57 112
58 - private 113 + # Private: Checks if an emoji icon exists in the image asset directory
  114 + #
  115 + # emoji - Identifier of the emoji as a string (e.g., "+1", "heart")
  116 + #
  117 + # Returns boolean
  118 + def valid_emoji?(emoji)
  119 + File.exists?(Rails.root.join('app', 'assets', 'images', 'emoji', "#{emoji}.png"))
  120 + end
59 121
60 # Private: Dispatches to a dedicated processing method based on reference 122 # Private: Dispatches to a dedicated processing method based on reference
61 # 123 #
lib/hooks/post-receive
1 #!/usr/bin/env bash 1 #!/usr/bin/env bash
2 2
3 -# This file was placed here by Gitlab. It makes sure that your pushed commits 3 +# This file was placed here by GitLab. It makes sure that your pushed commits
4 # will be processed properly. 4 # will be processed properly.
5 5
6 while read oldrev newrev ref 6 while read oldrev newrev ref
lib/tasks/bulk_import.rake
1 -IMPORT_DIRECTORY = 'import_projects'  
2 -  
3 -desc "Imports existing Git repos into new projects from the import_projects folder"  
4 -task :import_projects, [:email] => :environment do |t, args|  
5 - REPOSITORY_DIRECTORY = Gitlab.config.git_base_path  
6 1
  2 +desc "Imports existing Git repos from a directory into new projects in git_base_path"
  3 +task :import_projects, [:directory,:email] => :environment do |t, args|
7 user_email = args.email 4 user_email = args.email
8 - repos_to_import = Dir.glob("#{IMPORT_DIRECTORY}/*")  
9 - 5 + import_directory = args.directory
  6 + repos_to_import = Dir.glob("#{import_directory}/*")
  7 + git_base_path = Gitlab.config.git_base_path
10 puts "Found #{repos_to_import.length} repos to import" 8 puts "Found #{repos_to_import.length} repos to import"
11 9
12 imported_count = 0 10 imported_count = 0
@@ -14,11 +12,9 @@ task :import_projects, [:email] =&gt; :environment do |t, args| @@ -14,11 +12,9 @@ task :import_projects, [:email] =&gt; :environment do |t, args|
14 failed_count = 0 12 failed_count = 0
15 repos_to_import.each do |repo_path| 13 repos_to_import.each do |repo_path|
16 repo_name = File.basename repo_path 14 repo_name = File.basename repo_path
17 - repo_full_path = File.join(Rails.root, repo_path)  
18 15
19 puts " Processing #{repo_name}" 16 puts " Processing #{repo_name}"
20 -  
21 - clone_path = "#{REPOSITORY_DIRECTORY}/#{repo_name}.git" 17 + clone_path = "#{git_base_path}#{repo_name}.git"
22 18
23 if Dir.exists? clone_path 19 if Dir.exists? clone_path
24 if Project.find_by_code(repo_name) 20 if Project.find_by_code(repo_name)
@@ -30,7 +26,7 @@ task :import_projects, [:email] =&gt; :environment do |t, args| @@ -30,7 +26,7 @@ task :import_projects, [:email] =&gt; :environment do |t, args|
30 end 26 end
31 else 27 else
32 # Clone the repo 28 # Clone the repo
33 - unless clone_bare_repo_as_git(repo_full_path, clone_path) 29 + unless clone_bare_repo_as_git(repo_path, clone_path)
34 failed_count += 1 30 failed_count += 1
35 next 31 next
36 end 32 end
@@ -48,14 +44,17 @@ task :import_projects, [:email] =&gt; :environment do |t, args| @@ -48,14 +44,17 @@ task :import_projects, [:email] =&gt; :environment do |t, args|
48 puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})." 44 puts "Finished importing #{imported_count} projects (skipped #{skipped_count}, failed #{failed_count})."
49 end 45 end
50 46
51 -# Clones a repo as bare git repo using the git user 47 +# Clones a repo as bare git repo using the git_user
52 def clone_bare_repo_as_git(existing_path, new_path) 48 def clone_bare_repo_as_git(existing_path, new_path)
  49 + git_user = Gitlab.config.ssh_user
53 begin 50 begin
54 - sh "sudo -u git -i git clone --bare '#{existing_path}' #{new_path}" 51 + sh "sudo -u #{git_user} -i git clone --bare '#{existing_path}' #{new_path}"
55 true 52 true
56 - rescue 53 + rescue Exception=> msg
57 puts " ERROR: Faild to clone #{existing_path} to #{new_path}" 54 puts " ERROR: Faild to clone #{existing_path} to #{new_path}"
58 - false 55 + puts " Make sure #{git_user} can reach #{existing_path}"
  56 + puts " Exception-MSG: #{msg}"
  57 + false
59 end 58 end
60 end 59 end
61 60
lib/tasks/gitlab/write_hook.rake
1 namespace :gitlab do 1 namespace :gitlab do
2 namespace :gitolite do 2 namespace :gitolite do
3 - desc "GITLAB | Write GITLAB hook for gitolite" 3 + desc "GITLAB | Write GitLab hook for gitolite"
4 task :write_hooks => :environment do 4 task :write_hooks => :environment do
5 gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common") 5 gitolite_hooks_path = File.join(Gitlab.config.git_hooks_path, "common")
6 gitlab_hooks_path = Rails.root.join("lib", "hooks") 6 gitlab_hooks_path = Rails.root.join("lib", "hooks")
spec/factories.rb
@@ -11,6 +11,9 @@ module Factory @@ -11,6 +11,9 @@ module Factory
11 def self.new(type, *args) 11 def self.new(type, *args)
12 FactoryGirl.build(type, *args) 12 FactoryGirl.build(type, *args)
13 end 13 end
  14 + def self.attributes(type, *args)
  15 + FactoryGirl.attributes_for(type, *args)
  16 + end
14 end 17 end
15 18
16 FactoryGirl.define do 19 FactoryGirl.define do
spec/factories_spec.rb
1 require 'spec_helper' 1 require 'spec_helper'
2 2
3 -describe "Factories" do  
4 - describe 'User' do  
5 - it "builds a valid instance" do  
6 - build(:user).should be_valid  
7 - end  
8 -  
9 - it "builds a valid admin instance" do  
10 - build(:admin).should be_valid  
11 - end  
12 - end  
13 -  
14 - describe 'Project' do  
15 - it "builds a valid instance" do  
16 - build(:project).should be_valid  
17 - end  
18 - end  
19 -  
20 - describe 'Issue' do  
21 - it "builds a valid instance" do  
22 - build(:issue).should be_valid  
23 - end  
24 -  
25 - it "builds a valid closed instance" do  
26 - build(:closed_issue).should be_valid  
27 - end  
28 - end  
29 -  
30 - describe 'MergeRequest' do  
31 - it "builds a valid instance" do  
32 - build(:merge_request).should be_valid  
33 - end  
34 - end  
35 -  
36 - describe 'Note' do  
37 - it "builds a valid instance" do  
38 - build(:note).should be_valid  
39 - end  
40 - end  
41 -  
42 - describe 'Event' do  
43 - it "builds a valid instance" do  
44 - build(:event).should be_valid  
45 - end  
46 - end  
47 -  
48 - describe 'Key' do  
49 - it "builds a valid instance" do  
50 - build(:key).should be_valid  
51 - end  
52 -  
53 - it "builds a valid deploy key instance" do  
54 - build(:deploy_key).should be_valid  
55 - end  
56 -  
57 - it "builds a valid personal key instance" do  
58 - build(:personal_key).should be_valid  
59 - end  
60 - end  
61 -  
62 - describe 'Milestone' do  
63 - it "builds a valid instance" do  
64 - build(:milestone).should be_valid  
65 - end  
66 - end  
67 -  
68 - describe 'SystemHook' do  
69 - it "builds a valid instance" do  
70 - build(:system_hook).should be_valid  
71 - end  
72 - end  
73 -  
74 - describe 'ProjectHook' do  
75 - it "builds a valid instance" do  
76 - build(:project_hook).should be_valid  
77 - end  
78 - end  
79 -  
80 - describe 'Wiki' do  
81 - it "builds a valid instance" do  
82 - build(:wiki).should be_valid  
83 - end  
84 - end  
85 -  
86 - describe 'Snippet' do  
87 - it "builds a valid instance" do  
88 - build(:snippet).should be_valid 3 +FactoryGirl.factories.map(&:name).each do |factory_name|
  4 + describe "#{factory_name} factory" do
  5 + it 'should be valid' do
  6 + build(factory_name).should be_valid
89 end 7 end
90 end 8 end
91 end 9 end
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -208,6 +208,51 @@ describe GitlabMarkdownHelper do @@ -208,6 +208,51 @@ describe GitlabMarkdownHelper do
208 gfm(actual).should match(expected) 208 gfm(actual).should match(expected)
209 end 209 end
210 end 210 end
  211 +
  212 + describe "emoji" do
  213 + it "matches at the start of a string" do
  214 + gfm(":+1:").should match(/<img/)
  215 + end
  216 +
  217 + it "matches at the end of a string" do
  218 + gfm("This gets a :-1:").should match(/<img/)
  219 + end
  220 +
  221 + it "matches with adjacent text" do
  222 + gfm("+1 (:+1:)").should match(/<img/)
  223 + end
  224 +
  225 + it "has a title attribute" do
  226 + gfm(":-1:").should match(/title=":-1:"/)
  227 + end
  228 +
  229 + it "has an alt attribute" do
  230 + gfm(":-1:").should match(/alt=":-1:"/)
  231 + end
  232 +
  233 + it "has an emoji class" do
  234 + gfm(":+1:").should match('class="emoji"')
  235 + end
  236 +
  237 + it "sets height and width" do
  238 + actual = gfm(":+1:")
  239 + actual.should match(/width="20"/)
  240 + actual.should match(/height="20"/)
  241 + end
  242 +
  243 + it "keeps whitespace intact" do
  244 + gfm("This deserves a :+1: big time.").should match(/deserves a <img.+\/> big time/)
  245 + end
  246 +
  247 + it "ignores invalid emoji" do
  248 + gfm(":invalid-emoji:").should_not match(/<img/)
  249 + end
  250 +
  251 + it "should work independet of reference links (i.e. without @project being set)" do
  252 + @project = nil
  253 + gfm(":+1:").should match(/<img/)
  254 + end
  255 + end
211 end 256 end
212 257
213 describe "#link_to_gfm" do 258 describe "#link_to_gfm" do
spec/lib/gitolite_config_spec.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Gitlab::GitoliteConfig do
  4 + let(:gitolite) { Gitlab::GitoliteConfig.new }
  5 +
  6 + it { should respond_to :write_key }
  7 + it { should respond_to :rm_key }
  8 + it { should respond_to :update_project }
  9 + it { should respond_to :update_project! }
  10 + it { should respond_to :update_projects }
  11 + it { should respond_to :destroy_project }
  12 + it { should respond_to :destroy_project! }
  13 + it { should respond_to :apply }
  14 + it { should respond_to :admin_all_repo }
  15 + it { should respond_to :admin_all_repo! }
  16 +end
spec/lib/gitolite_spec.rb 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +require 'spec_helper'
  2 +
  3 +describe Gitlab::Gitolite do
  4 + let(:project) { double('Project', path: 'diaspora') }
  5 + let(:gitolite_config) { double('Gitlab::GitoliteConfig') }
  6 + let(:gitolite) { Gitlab::Gitolite.new }
  7 +
  8 + before do
  9 + gitolite.stub(config: gitolite_config)
  10 + end
  11 +
  12 + it { should respond_to :set_key }
  13 + it { should respond_to :remove_key }
  14 +
  15 + it { should respond_to :update_repository }
  16 + it { should respond_to :create_repository }
  17 + it { should respond_to :remove_repository }
  18 +
  19 + it { gitolite.url_to_repo('diaspora').should == Gitlab.config.ssh_path + "diaspora.git" }
  20 +
  21 + it "should call config update" do
  22 + gitolite_config.should_receive(:update_project!)
  23 + gitolite.update_repository project
  24 + end
  25 +end
spec/mailers/notify_spec.rb
@@ -24,7 +24,7 @@ describe Notify do @@ -24,7 +24,7 @@ describe Notify do
24 end 24 end
25 25
26 it 'has the correct subject' do 26 it 'has the correct subject' do
27 - should have_subject /^gitlab \| Account was created for you$/ 27 + should have_subject /^gitlab \| Account was created for you$/i
28 end 28 end
29 29
30 it 'contains the new user\'s login name' do 30 it 'contains the new user\'s login name' do
spec/models/note_spec.rb
@@ -35,6 +35,16 @@ describe Note do @@ -35,6 +35,16 @@ describe Note do
35 note = Factory(:note, note: "-1 for this") 35 note = Factory(:note, note: "-1 for this")
36 note.should_not be_upvote 36 note.should_not be_upvote
37 end 37 end
  38 +
  39 + it "recognizes a +1 emoji as a vote" do
  40 + note = build(:note, note: ":+1: for this")
  41 + note.should be_upvote
  42 + end
  43 +
  44 + it "recognizes a neutral emoji note" do
  45 + note = build(:note, note: "I would :+1: this, but I don't want to")
  46 + note.should_not be_upvote
  47 + end
38 end 48 end
39 49
40 let(:project) { create(:project) } 50 let(:project) { create(:project) }
spec/models/users_project_spec.rb
@@ -10,7 +10,7 @@ describe UsersProject do @@ -10,7 +10,7 @@ describe UsersProject do
10 let!(:users_project) { create(:users_project) } 10 let!(:users_project) { create(:users_project) }
11 11
12 it { should validate_presence_of(:user_id) } 12 it { should validate_presence_of(:user_id) }
13 - it { should validate_uniqueness_of(:user_id).scoped_to(:project_id) } 13 + it { should validate_uniqueness_of(:user_id).scoped_to(:project_id).with_message(/already exists/) }
14 14
15 it { should validate_presence_of(:project_id) } 15 it { should validate_presence_of(:project_id) }
16 end 16 end
spec/requests/api/projects_spec.rb
@@ -30,38 +30,40 @@ describe Gitlab::API do @@ -30,38 +30,40 @@ describe Gitlab::API do
30 30
31 describe "POST /projects" do 31 describe "POST /projects" do
32 it "should create new project without code and path" do 32 it "should create new project without code and path" do
33 - lambda {  
34 - name = "foo"  
35 - post api("/projects", user), {  
36 - name: name  
37 - }  
38 - response.status.should == 201  
39 - json_response["name"].should == name  
40 - json_response["code"].should == name  
41 - json_response["path"].should == name  
42 - }.should change{Project.count}.by(1)  
43 - end  
44 - it "should create new project" do  
45 - lambda {  
46 - name = "foo"  
47 - path = "bar"  
48 - code = "bazz"  
49 - post api("/projects", user), {  
50 - code: code,  
51 - path: path,  
52 - name: name  
53 - }  
54 - response.status.should == 201  
55 - json_response["name"].should == name  
56 - json_response["path"].should == path  
57 - json_response["code"].should == code  
58 - }.should change{Project.count}.by(1)  
59 - end  
60 - it "should not create project without name" do  
61 - lambda {  
62 - post api("/projects", user)  
63 - response.status.should == 404  
64 - }.should_not change{Project.count} 33 + expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
  34 + end
  35 +
  36 + it "should not create new project without name" do
  37 + expect { post api("/projects", user) }.to_not change {Project.count}
  38 + end
  39 +
  40 + it "should respond with 201 on success" do
  41 + post api("/projects", user), name: 'foo'
  42 + response.status.should == 201
  43 + end
  44 +
  45 + it "should repsond with 404 on failure" do
  46 + post api("/projects", user)
  47 + response.status.should == 404
  48 + end
  49 +
  50 + it "should assign attributes to project" do
  51 + project = Factory.attributes(:project, {
  52 + path: 'path',
  53 + code: 'code',
  54 + description: Faker::Lorem.sentence,
  55 + default_branch: 'stable',
  56 + issues_enabled: false,
  57 + wall_enabled: false,
  58 + merge_requests_enabled: false,
  59 + wiki_enabled: false
  60 + })
  61 +
  62 + post api("/projects", user), project
  63 +
  64 + project.each_pair do |k,v|
  65 + json_response[k.to_s].should == v
  66 + end
65 end 67 end
66 end 68 end
67 69
spec/support/gitolite_stub.rb
@@ -17,7 +17,7 @@ module GitoliteStub @@ -17,7 +17,7 @@ module GitoliteStub
17 ) 17 )
18 18
19 gitolite_admin = double( 19 gitolite_admin = double(
20 - 'Gitolite::GitoliteAdmin', 20 + 'Gitolite::GitoliteAdmin',
21 config: gitolite_config, 21 config: gitolite_config,
22 save: true, 22 save: true,
23 ) 23 )
@@ -27,9 +27,21 @@ module GitoliteStub @@ -27,9 +27,21 @@ module GitoliteStub
27 end 27 end
28 28
29 def stub_gitlab_gitolite 29 def stub_gitlab_gitolite
30 - gitlab_gitolite = Gitlab::Gitolite.new  
31 - Gitlab::Gitolite.stub(new: gitlab_gitolite)  
32 - gitlab_gitolite.stub(configure: ->() { yield(self) })  
33 - gitlab_gitolite.stub(update_keys: true) 30 + gitolite_config = double('Gitlab::GitoliteConfig')
  31 + gitolite_config.stub(
  32 + apply: ->() { yield(self) },
  33 + write_key: true,
  34 + rm_key: true,
  35 + update_projects: true,
  36 + update_project: true,
  37 + update_project!: true,
  38 + destroy_project: true,
  39 + destroy_project!: true,
  40 + admin_all_repo: true,
  41 + admin_all_repo!: true,
  42 +
  43 + )
  44 +
  45 + Gitlab::GitoliteConfig.stub(new: gitolite_config)
34 end 46 end
35 end 47 end