Mostly added documentation, but some minor changes.

This commit is contained in:
simon 2017-08-09 13:12:44 +01:00
parent f54a2d46f3
commit 54dcdd5b4c
24 changed files with 395 additions and 223 deletions

View file

@ -28,7 +28,8 @@
{ {
:site-title "Smeagol" ;; overall title of the site, used in page headings :site-title "Smeagol" ;; overall title of the site, used in page headings
:default-locale "en-GB" ;; default language used for messages :default-locale "en-GB" ;; default language used for messages
:formatters {"vega" smeagol.formatting/process-vega :formatters {"vega" smeagol.formatting/process-vega
"vis" smeagol.formatting/process-vega "vis" smeagol.formatting/process-vega
"mermaid" smeagol.formatting/process-mermaid} "mermaid" smeagol.formatting/process-mermaid
"backticks" smeagol.formatting/process-backticks}
} }

1
resources/i18n/en.edn Symbolic link
View file

@ -0,0 +1 @@
en-GB.edn

View file

@ -0,0 +1,44 @@
## Prerequisites
You will need [Leiningen](https://github.com/technomancy/leiningen) 2.0 or above installed.
You will need [node](https://nodejs.org/en/) and [bower](https://bower.io/) installed.
## Running
To start a web server for the application, run:
lein bower install
lein ring server
Alternatively, if you want to deploy to a servlet container (which I would strongly recommend), the simplest thing is to run:
lein bower install
lein ring uberwar
(a command which I'm sure Smeagol would entirely appreciate) and deploy the resulting war file.
## Experimental Docker image
You can now run Smeagol as a [Docker](http://www.docker.com) image. Read more about [[Using the Docker Image]].
To run my Docker image, use
docker run simonbrooke/smeagol
Smeagol will run, obviously, on the IP address of your Docker image, on port 8080. To find the IP address, start the image using the command above and then use
docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q)
Suppose this prints '10.10.10.10', then the URL to browse to will be http://10.10.10.10:8080/smeagol/
This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content.
To build your own Docker image, run:
lein clean
lein bower install
lein ring uberwar
lein docker build
This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish.

View file

@ -0,0 +1,99 @@
A system of pluggable, extensible formatters is supported. In normal markdown, code blocks may be delimited by three backticks at start and end, and often the syntax of the code can be indicated by a token immediately following the opening three backticks. This has been extended to allow custom formatters to be provided for such code blocks. Two example formatters are provided:
## The Vega formatter
Inspired by [visdown](http://visdown.amitkaps.com/) and [vega-lite](https://vega.github.io/vega-lite/docs/), the Vega formatter allows you to embed vega data visualisations into Smeagol pages. The graph description should start with a line comprising three back-ticks and then the word '`vega`', and end with a line comprising just three backticks.
Here's an example cribbed in its entirety from [here](http://visdown.amitkaps.com/london):
### Flight punctuality at London airports
```vega
data:
url: "data/london.csv"
transform:
-
filter: datum.year == 2016
mark: rect
encoding:
x:
type: nominal
field: source
y:
type: nominal
field: dest
color:
type: quantitative
field: flights
aggregate: sum
```
Data files can be uploaded in the same way as images, by using the **upload a file** link.
## The Mermaid formatter
Graphs can now be embedded in a page using the [Mermaid](http://knsv.github.io/mermaid/index.html) graph description language. The graph description should start with a line comprising three back-ticks and then the word `mermaid`, and end with a line comprising just three backticks.
Here's an example culled from the Mermaid documentation.
### GANTT Chart
```mermaid
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
```
## Writing your own custom formatters
A custom formatter is simply a Clojure function which takes a string and an integer as arguments and produces a string as output. The string is the text the user has typed into their markdown; the integer is simply a number you can use to keep track of which addition to the page this is, in order, for example, to fix up some JavaScript to render it.
For example, here's the formatter which handles the Vega charts:
(defn process-vega
"Process this `vega-src` string, assumed to be in YAML format, into a specification
of a Vega chart, and add the plumbing to render it."
[^String vega-src ^Integer index]
(str
"<div class='data-visualisation' id='vis" index "'></div>\n"
"<script>\n//<![CDATA[\nvar vl"
index
" = "
(yaml->json (str "$schema: https://vega.github.io/schema/vega-lite/v2.json\n" vega-src))
";\nvega.embed('#vis"
index
"', vl"
index
");\n//]]\n</script>"))
### Configuring Smeagol to use your formatter
To add your own formatter, compile it into a jar file which is on the classpath - it does *not* have to be part of the Smeagol project directly - and then edit the value of the key `:formatters` in the file `config.edn`; whose standard definition is:
:formatters {"vega" smeagol.formatting/process-vega
"vis" smeagol.formatting/process-vega
"mermaid" smeagol.formatting/process-mermaid}
The added key should be the word which will follow the opening three backticks of your code block, and the value of that key should be a symbol which evaluates to the function you have written. So suppose your formatter was called `my-magic-formatter`; you'd written it in a namespace called `magic.core`; and you wanted users to identify it with the word `magic`, you'd add the following to the `:formatters` map:
"magic" magic.core/my-magic-formatter
Users could then put a section in their markdown text:
```backticks magic
wingardium leviosa
```
and your function would be called with "wingardium leviosa" as the first argument.

View file

@ -8,153 +8,34 @@ So at this stage Smeagol is a Wiki engine written in Clojure which uses Markdown
## Status ## Status
Smeagol is now a fully working small Wiki engine, and meets my own immediate needs. Smeagol is now a fully working small Wiki engine, and meets my own immediate needs.
## Using Smeagol
Read the [[User Documentation]] for an introduction to all Smeagol's features.
## Markup syntax ## Markup syntax
Smeagol uses the Markdown format as provided by [markdown-clj](https://github.com/yogthos/markdown-clj), with the addition that anything enclosed in double square brackets, \[\[like this\]\], will be treated as a link into the wiki itself. Smeagol uses the Markdown format as provided by [markdown-clj](https://github.com/yogthos/markdown-clj), with the addition that anything enclosed in double square brackets, \[\[like this\]\], will be treated as a link into the wiki itself. Read more about [[Extensible Markup]].
### Pluggable extensible markup
A system of pluggable, extensible formatters is supported. In normal markdown, code blocks may be delimited by three backticks at start and end, and often the syntax of the code can be indicated by a token immediately following the opening three backticks. This has been extended to allow custom formatters to be provided for such code blocks. Two example formatters are provided:
#### The Vega formatter
Inspired by [visdown](http://visdown.amitkaps.com/) and [vega-lite](https://vega.github.io/vega-lite/docs/), the Vega formatter allows you to embed vega data visualisations into Smeagol pages. The graph description should start with a line comprising three back-ticks and then the word '`vega`', and end with a line comprising just three backticks.
Here's an example cribbed in its entirety from [here](http://visdown.amitkaps.com/london):
##### Flight punctuality at London airports
```vega
data:
url: "data/london.csv"
transform:
-
filter: datum.year == 2016
mark: rect
encoding:
x:
type: nominal
field: source
y:
type: nominal
field: dest
color:
type: quantitative
field: flights
aggregate: sum
```
Data files can be uploaded in the same way as images, by using the **upload a file** link.
Note that this visualisation will not be rendered in the GitHub wiki, as it doesn't have Smeagol's data visualisation magic. This is what it should look like:
![Example visualisation](https://github.com/simon-brooke/smeagol/blob/develop/resources/public/data/london.png?raw=true)
#### The Mermaid formatter
Graphs can now be embedded in a page using the [Mermaid](http://knsv.github.io/mermaid/index.html) graph description language. The graph description should start with a line comprising three back-ticks and then the word `mermaid`, and end with a line comprising just three backticks.
Here's an example culled from the Mermaid documentation.
##### GANTT Chart
```mermaid
gantt
dateFormat YYYY-MM-DD
title Adding GANTT diagram functionality to mermaid
section A section
Completed task :done, des1, 2014-01-06,2014-01-08
Active task :active, des2, 2014-01-09, 3d
Future task : des3, after des2, 5d
Future task2 : des4, after des3, 5d
section Critical tasks
Completed task in the critical line :crit, done, 2014-01-06,24h
Implement parser and jison :crit, done, after des1, 2d
Create tests for parser :crit, active, 3d
Future task in critical line :crit, 5d
Create tests for renderer :2d
Add to mermaid :1d
```
To add your own formatter, compile it into a jar file which is on the classpath - it does *not* have to be part of the Smeagol project directly, and then edit the value of the key `:formatters` in the file `config.edn`; whose standard definition is:
:formatters {"vega" smeagol.formatting/process-vega
"vis" smeagol.formatting/process-vega
"mermaid" smeagol.formatting/process-mermaid}
The added key should be the word which will follow the opening three backticks of your code block, and the value of that key should be a symbol which evaluates to a function which can format the code block as required.
## Security and authentication ## Security and authentication
Security is now greatly improved. There is a file called *passwd* in the *resources* directory, which contains a clojure map which maps usernames to maps with plain-text passwords and emails thus: Smeagol now has good security and authentication. While the initial password supplied with the system is not encrypted, when it is changed it will be; and passwords for new users added through the user administration pages are encrypted. Read more about [[Security and authentication]].
{:admin {:password "admin" :email "admin@localhost" :admin true}
:adam {:password "secret" :email "adam@localhost"}}
that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, nor in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way.
## Images ## Images
You can (if you're logged in) upload files, including images, using the **Upload a file** link on the top menu bar. You can link to an uploaded image, or other images already available on the web, like this: You can (if you're logged in) upload files, including images, using the **Upload a file** link on the top menu bar. You can link to an uploaded image, or to other images already available on the web, like this:
![Smeagol](http://vignette3.wikia.nocookie.net/lotr/images/e/e1/Gollum_Render.png/revision/latest?cb=20141218075509) ![Smeagol](http://vignette3.wikia.nocookie.net/lotr/images/e/e1/Gollum_Render.png/revision/latest?cb=20141218075509)
## Advertisement ## Running Smeagol
If you like what you see here, I am available for work on open source Clojure projects. You can run Smeagol from the [[Docker Image]]; alternatively you can run it from an executable jar file or as a war file in a servlet container. Read how in [[Developing Smeagol]].
### Phoning home ## Developing Smeagol
Smeagol currently requests the WEFT logo in the page footer from my home site. This is mainly so I can get a feel for how many people are using the product. If you object to this, edit the file Smeagol is an open source project; you're entitled to make changes yourself. Read more about [[Developing Smeagol]].
resources/templates/base.html
and replace the line
<img height="16" width="16" alt="The Web Engineering Factory &amp; Toolworks" src="http://www.weft.scot/images/weft.logo.64.png"> Developed by <a href="http://www.weft.scot/">WEFT</a>
with the line
<img height="16" width="16" alt="The Web Engineering Factory &amp; Toolworks" src="img/weft.logo.64.png"> Developed by <a href="http://www.weft.scot/">WEFT</a>
## License ## License
Copyright © 2014-2015 Simon Brooke. Licensed under the GNU General Public License, Copyright © 2014-2017 Simon Brooke. Licensed under the GNU General Public License,
version 2.0 or (at your option) any later version. If you wish to incorporate version 2.0 or (at your option) any later version. If you wish to incorporate
parts of Smeagol into another open source project which uses a less restrictive parts of Smeagol into another open source project which uses a less restrictive
license, please contact me; I'm open to dual licensing it. license, please contact me; I'm open to dual licensing it.
## Prerequisites ## Phoning home
You will need [Leiningen](https://github.com/technomancy/leiningen) 2.0 or above installed. Smeagol does currently fetch one image from my home site. Read more about [[Phoning Home]], and how to prevent it (if you want to).
You will need [node](https://nodejs.org/en/) and [bower](https://bower.io/) installed. ## Advertisement
If you like what you see here, I am available for work on open source Clojure projects.
## Running
To start a web server for the application, run:
lein bower install
lein ring server
Alternatively, if you want to deploy to a servlet container (which I would strongly recommend), the simplest thing is to run:
lein bower install
lein ring uberwar
(a command which I'm sure Smeagol would entirely appreciate) and deploy the resulting war file.
## Experimental Docker image
You can now run Smeagol as a [Docker](http://www.docker.com) image. To run my Docker image, use
docker run simonbrooke/smeagol
Smeagol will run, obviously, on the IP address of your Docker image, on port 8080. To find the IP address, start the image using the command above and then use
docker inspect --format '{{ .NetworkSettings.IPAddress }}' $(docker ps -q)
Suppose this prints '10.10.10.10', then the URL to browse to will be http://10.10.10.10:8080/smeagol/
This image is _experimental_, but it does seem to work fairly well. What it does **not** yet do, however, is push the git repository to a remote location, so when you tear the Docker image down your edits will be lost. My next objective for this image is for it to have a cammand line parameter being the git address of a repository from which it can initialise the Wiki content, and to which it will periodically push local changes to the Wiki content.
To build your own Docker image, run:
lein clean
lein bower install
lein ring uberwar
lein docker build
This will build a new Docker image locally; you can, obviously, push it to your own Docker repository if you wish.

View file

@ -0,0 +1,11 @@
Smeagol currently requests the WEFT logo in the page footer from my home site. This is mainly so I can get a feel for how many people are using the product. If you object to this, edit the file
resources/templates/base.html
and replace the line
<img height="16" width="16" alt="The Web Engineering Factory &amp; Toolworks" src="http://www.weft.scot/images/weft.logo.64.png"> Developed by <a href="http://www.weft.scot/">WEFT</a>
with the line
<img height="16" width="16" alt="The Web Engineering Factory &amp; Toolworks" src="img/weft.logo.64.png"> Developed by <a href="http://www.weft.scot/">WEFT</a>

View file

@ -0,0 +1,6 @@
Security is now greatly improved. There is a file called *passwd* in the *resources* directory, which contains a clojure map which maps usernames to maps with plain-text passwords and emails thus:
{:admin {:password "admin" :email "admin@localhost" :admin true}
:adam {:password "secret" :email "adam@localhost"}}
that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, nor in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way.

View file

@ -0,0 +1,124 @@
## If you're using a small device
If you're using a small device, like a mobile phone, the top menu isn't usually displayed. Instead there will be an image like this:
![Menu icon](/img/three-lines.png)
at the top left of the page. Touching this image will cause the top menu to be displayed, and it will have all the options described in this documentation.
## Logging in
If you are not logged in, there will be an option `Log in` on the top menu. Note that if you're not an English language speaker, the menu items may be in your own language (provided we have a suitable language file). You must log in to edit pages, to change your password, or to perform administration.
Selecting the 'Log in' option will take you to the log in page. This will prompt you for your username and password. If you have just set up a new instance of Smeagol, your username will be `admin` and your password will be `admin`. **Note** It is very important to change this default password after logging in.
+-------------------------------------------------------------------------+
| +----------------------------------+ |
| Your username: | | |
| +----------------------------------+ |
| Your password: | | |
| +----------------------------------+ |
| +-----------+ |
| To edit this wiki | Log in! | |
| +-----------+ |
+-------------------------------------------------------------------------+
Once you have entered your username and password, select the green `Log in!` button, or press `return` on your keyboard.
### Changing your password
To change your password, select the `Change password` option from the top menu. This will take you to the `Change password for...` page. This will prompt you for your (old) password, and your new password, twice. Complete the form and select the green `Change password!` button, or hit return.
+-------------------------------------------------------------------------+
| +----------------------------------+ |
| Your password: | | |
| +----------------------------------+ |
| New password: | | |
| +----------------------------------+ |
| And again: | | |
| +----------------------------------+ |
| +--------------------+ |
| To change your password | Change password! | |
| +--------------------+ |
+-------------------------------------------------------------------------+
If there is a problem (for example, the password wasn't long enough, or your new passwords didn't match), a message will show in red below the header of the page to explain the problem. Complete the form again.
If the form was submitted successfully and your password is changed, a message will be shown in green below the header of the page confirming this.
## Viewing page history
You can view the edit history of any page in the Wiki. At the top right of the content area, you will find a link `History`. Selecting this will take you to a page listing all the edits that have been made. Each row shows you:
* When the change was made
* What was changed (and who changed it)
It also provides a link `Show Version`, and a link `What's changed since?`
### Viewing a specific version
Selecting the `Show Version` link from any version in the page history will open the version of the page exactly as it was immediately after that edit. Selecting the `What's changed since?` link will show a page which highlights all the changes made to the page since that edit, with added text shown in green and deleted text in red.
## Editing pages
If you are logged in you can edit any page in the Wiki. At the top right of the content area, you will find a link `Edit this page`. Selecting this opens the page in the editor.
The editor is not strictly 'what you see is what you get', but it's fairly close to it. Icons on the ribbon above the content area allow you to apply simple styling. There are some prompts in the sidebar which will help with more complicate things.
### Markup syntax
Smeagol uses the Markdown format as provided by [markdown-clj](https://github.com/yogthos/markdown-clj), with the addition that anything enclosed in double square brackets, \[\[like this\]\], will be treated as a link into the wiki itself. Smeagol also supports [[Extensible Markup]].
## Uploading files
To upload a file (including an image file), select the link `Upload a file` from the top menu. **Warning:** do not do this while you are editing a page, or you will lose your edit!
Selecting the link will take you to the `Upload a file` page. This will prompt you for the file you wish to upload. Select your file, and then select the green `Save!` button.
After your file has uploaded, you will be shown a link which can be copied and pasted into a Wiki page to link to that file.
You must be logged in to upload files.
## Administering users
If you are an administrator, you can administer the users who are entitled to edit and administer the Wiki. When you are logged in, there will be a a link `Edit users` on the top menu. Selecting this will take you to the `Edit users` page which lists users, with an `Edit...` and a `Delete...` link for each. Below the existing users will be a link `Add new user`.
### Editing a user
Selecting the `Edit...` link for any user from the `Edit users` page, or the `Add new user` link from the same page, will take you to the `Edit user` form.
This page has the following inputs:
+-------------------------------------------------------------------------+
| +----------------------------------+ |
| Username: | | |
| +----------------------------------+ |
| New password: | | |
| +----------------------------------+ |
| And again: | | |
| +----------------------------------+ |
| Email address: | | |
| +----------------------------------+ |
| Is Administrator? [ ] |
| +---------+ |
| When you have finished editing | Save! | |
| +---------+ |
+-------------------------------------------------------------------------+
#### To add a new user
When using this form after selecting the `Add new user` link, all fields will be blank. Complete at least the fields `Username`, `New password`, `And again`, and `Email address`. If the new user is to be an administrator, check the box labelled `Is Administrator`. Finally, select the green button marked `Save!`. Your new user will be saved.
#### To edit an existing user
When using this form after selecting the `Edit...` link against a particular user, the `Username` field will already be filled in (and you won't be able to edit it). The `Email address` field will also probably be filled in. If the user is an administrator, the `Is Administrator` box will be checked. The `New password` and `And again` fields will be blank. You may alter the email address or change the `Is Administrator` status.
#### To change the password of an existing user
Smeagol does not have a mechanism to allow users to reset their own password if they have forgotten it. Instead, they will have to ask an administrator to do this.
On the `Edit user` page for the existing user, enter their new password in the fields `New password` and `And again`; then select the green button marked `Save!`. **Warning** If you do not want to change the password, leave these fields blank!
## To log out
When you've finished editing the Wiki, you should log out. Select the `Log out` link from the top menu. This will take you to a very simple form:
+-------------------------------------------------------------------------+
| +------------+ |
| When you have finished editing | Log out! | |
| +------------+ |
+-------------------------------------------------------------------------+
Select the red `Log out!` button to log out.

View file

@ -35,7 +35,7 @@ del {
} }
div.content, form, p, pre, h1, h2, h3, h4, h5 { div.content, form, p, pre, h1, h2, h3, h4, h5 {
padding: 0.25em 5%; padding: 0.1em 5% 0 5%;
} }
dl, menu, ol, table, ul { dl, menu, ol, table, ul {

View file

@ -2,7 +2,6 @@
{% block content %} {% block content %}
<div id="content" class="auth"> <div id="content" class="auth">
<form action="{{servlet-context}}/auth" method="POST"> <form action="{{servlet-context}}/auth" method="POST">
{% csrf-field %}
<input type="hidden" name="redirect-to" value="{{redirect-to}}"/> <input type="hidden" name="redirect-to" value="{{redirect-to}}"/>
{% if user %} {% if user %}
<p class="widget"> <p class="widget">

View file

@ -3,10 +3,10 @@
{% block content %} {% block content %}
<div id="content" class="edit"> <div id="content" class="edit">
<form action="{{servlet-context}}/edit-user" method="POST"> <form action="{{servlet-context}}/edit-user" method="POST">
<p class="widget"> <p class="widget">
<label for="target">{{config.username-prompt}}</label> <label for="target">{{config.username-prompt}}</label>
<input type="text" name="target" id="target" value="{{target}}" required/> <input type="text" name="target" id="target" value="{{target}}" required {% ifunequal target "" %}disabled{% endifunequal %}/>
</p> </p>
<p class="widget"> <p class="widget">
<label for="pass1">{{config.new-pass-prompt}}</label> <label for="pass1">{{config.new-pass-prompt}}</label>
<input name="pass1" id="pass1" type="password"/> <input name="pass1" id="pass1" type="password"/>

View file

@ -4,10 +4,11 @@
<div id="content"> <div id="content">
<table> <table>
<tr> <tr>
<th>{{config.edit-col-hdr}}</th><th>{{config.del-col-hdr}}</th> <th/><th>{{config.edit-col-hdr}}</th><th>{{config.del-col-hdr}}</th>
</tr> </tr>
{% for user in users %} {% for user in users %}
<tr> <tr>
<td>{{user}}</td>
<td><a href="edit-user?target={{user}}">{{config.edit-col-hdr}} {{user}}</a></td> <td><a href="edit-user?target={{user}}">{{config.edit-col-hdr}} {{user}}</a></td>
<td><a href="delete-user?target={{user}}">{{config.del-col-hdr}} {{user}}</a></td> <td><a href="delete-user?target={{user}}">{{config.del-col-hdr}} {{user}}</a></td>
</tr> </tr>
@ -15,6 +16,7 @@
<tr> <tr>
<td><a href="edit-user">{{config.add-user-label}}</a></td> <td><a href="edit-user">{{config.add-user-label}}</a></td>
<td></td> <td></td>
<td></td>
</tr> </tr>
</table> </table>
</div> </div>

View file

@ -41,7 +41,7 @@
(starts-with? line "-") (str "<p><del>" (subs line 1) "</del></p>") (starts-with? line "-") (str "<p><del>" (subs line 1) "</del></p>")
(starts-with? line "@@") "</div><div class='change'>" (starts-with? line "@@") "</div><div class='change'>"
(starts-with? line "\\") (str "<p class='warn'>" (subs line 1) "</p>") (starts-with? line "\\") (str "<p class='warn'>" (subs line 1) "</p>")
:true (str "<p>" line "</p>"))) true (str "<p>" line "</p>")))
(defn diff2html (defn diff2html

View file

@ -5,11 +5,7 @@
[clojure.string :as cs] [clojure.string :as cs]
[cemerick.url :refer (url url-encode url-decode)] [cemerick.url :refer (url url-encode url-decode)]
[clj-yaml.core :as yaml] [clj-yaml.core :as yaml]
[noir.io :as io]
[noir.session :as session]
[markdown.core :as md] [markdown.core :as md]
[taoensso.timbre :as timbre]
[smeagol.authenticate :as auth]
[smeagol.configuration :refer [config]])) [smeagol.configuration :refer [config]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -73,8 +69,8 @@
(defn process-vega (defn process-vega
"Process this `vega-source` string, assumed to be in YAML format, into a specification "Process this `vega-src` string, assumed to be in YAML format, into a specification
of a Vega chart, and add the plumbing to render it." of a Vega chart, and add the plumbing to render it."
[^String vega-src ^Integer index] [^String vega-src ^Integer index]
(str (str
"<div class='data-visualisation' id='vis" index "'></div>\n" "<div class='data-visualisation' id='vis" index "'></div>\n"
@ -82,7 +78,11 @@
index index
" = " " = "
(yaml->json (str "$schema: https://vega.github.io/schema/vega-lite/v2.json\n" vega-src)) (yaml->json (str "$schema: https://vega.github.io/schema/vega-lite/v2.json\n" vega-src))
";\nvega.embed('#vis" index "', vl" index ");\n//]]\n</script>")) ";\nvega.embed('#vis"
index
"', vl"
index
");\n//]]\n</script>"))
(defn process-mermaid (defn process-mermaid
@ -93,6 +93,13 @@
"\n</div>")) "\n</div>"))
(defn process-backticks
"Effectively, escape the backticks surrounding this `text`, by protecting them
from the `md->html` filter."
[^String text ^Integer index]
(str "<pre class=\"backticks\">```" (.trim text) "\n```</pre>"))
(defn get-first-token (defn get-first-token
"Return the first space-separated token of this `string`." "Return the first space-separated token of this `string`."
[^String string] [^String string]
@ -106,12 +113,12 @@
`:inclusions`, a map of constructed keywords to inclusion specifications, `:inclusions`, a map of constructed keywords to inclusion specifications,
and `:text`, an HTML text string with the keywords present where the and `:text`, an HTML text string with the keywords present where the
corresponding inclusion should be inserted." corresponding inclusion should be inserted."
[index result fragments processed] [index result fragment fragments processed]
(process-text (process-text
(+ index 1) (+ index 1)
result result
(rest fragments) fragments
(cons (first fragments) processed))) (cons fragment processed)))
(defn- apply-formatter (defn- apply-formatter
@ -125,21 +132,21 @@
[index result fragments processed fragment token formatter] [index result fragments processed fragment token formatter]
(let (let
[kw (keyword (str "inclusion-" index))] [kw (keyword (str "inclusion-" index))]
(process-text (process-text
(+ index 1) (+ index 1)
(assoc (assoc
result result
:inclusions :inclusions
(assoc (assoc
(:inclusions result) (:inclusions result)
kw kw
(apply (apply
formatter formatter
(list (list
(subs fragment (count token)) (subs fragment (count token))
index)))) index))))
(rest fragments) (rest fragments)
(cons kw processed)))) (cons kw processed))))
(defn process-text (defn process-text
@ -154,19 +161,22 @@
(process-text 0 {:inclusions {}} (cs/split text #"```") '())) (process-text 0 {:inclusions {}} (cs/split text #"```") '()))
([index result fragments processed] ([index result fragments processed]
(let [fragment (first fragments) (let [fragment (first fragments)
;; if I didn't find a formatter for a back-tick marked fragment,
;; I need to put the backticks back in.
remarked (if (odd? index) (str "```" fragment "\n```") fragment)
first-token (get-first-token fragment) first-token (get-first-token fragment)
formatter (eval ((:formatters config) first-token))] formatter (eval ((:formatters config) first-token))]
(cond (cond
(empty? fragments) (empty? fragments)
(assoc result :text (assoc result :text
(local-links (local-links
(md/md-to-html-string (md/md-to-html-string
(cs/join "\n\n" (reverse processed)) (cs/join "\n\n" (reverse processed))
:heading-anchors true))) :heading-anchors true)))
formatter formatter
(apply-formatter index result fragments processed fragment first-token formatter) (apply-formatter index result fragments processed fragment first-token formatter)
true true
(process-markdown-fragment index result fragments processed))))) (process-markdown-fragment index result remarked (rest fragments) processed)))))
(defn reintegrate-inclusions (defn reintegrate-inclusions

View file

@ -7,12 +7,10 @@
[smeagol.session-manager :as session-manager] [smeagol.session-manager :as session-manager]
[noir.response :refer [redirect]] [noir.response :refer [redirect]]
[noir.util.middleware :refer [app-handler]] [noir.util.middleware :refer [app-handler]]
[noir.util.route :refer [restricted]]
[noir.session :as session] [noir.session :as session]
[ring.middleware.defaults :refer [site-defaults]] [ring.middleware.defaults :refer [site-defaults]]
[compojure.route :as route] [compojure.route :as route]
[taoensso.timbre :as timbre] [taoensso.timbre :as timbre]
[taoensso.timbre.appenders.core :as appenders]
[taoensso.timbre.appenders.3rd-party.rotor :as rotor] [taoensso.timbre.appenders.3rd-party.rotor :as rotor]
[selmer.parser :as parser] [selmer.parser :as parser]
[environ.core :refer [env]] [environ.core :refer [env]]

View file

@ -80,32 +80,33 @@
(defn diff (defn diff
"Find the diff in the file at `file-path` within the repository at "Find the diff in the file at `file-path` within the repository at
`git-directory-path` between versions `older` and `newer` or between the specified `git-directory-path` between versions `older` and `newer` or between the specified
`version` and the current version of the file. Returns the diff as a string. `version` and the current version of the file. Returns the diff as a string.
Based on JGit Cookbook ShowFileDiff." Based on JGit Cookbook ShowFileDiff."
([^String git-directory-path ^String file-path ^String version] ([^String git-directory-path ^String file-path ^String version]
(diff git-directory-path file-path version (diff git-directory-path file-path version
(:id (first (find-history git-directory-path file-path))))) (:id (first (find-history git-directory-path file-path)))))
([^String git-directory-path ^String file-path ^String older ^String newer] ([^String git-directory-path ^String file-path ^String older ^String newer]
(let [git-r (git/load-repo git-directory-path) (let [git-r (git/load-repo git-directory-path)
old-parse (prepare-tree-parser git-r older) old-parse (prepare-tree-parser git-r older)
new-parse (prepare-tree-parser git-r newer) new-parse (prepare-tree-parser git-r newer)
out (java.io.ByteArrayOutputStream.)] out (java.io.ByteArrayOutputStream.)]
(map (doall
#(let [formatter (DiffFormatter. out)] (map
(.setRepository formatter (.getRepository git-r)) #(let [formatter (DiffFormatter. out)]
(.format formatter %) (.setRepository formatter (.getRepository git-r))
%) (.format formatter %)
(.call %)
(.setOutputStream (.call
(.setPathFilter (.setOutputStream
(.setNewTree (.setPathFilter
(.setOldTree (.diff git-r) old-parse) (.setNewTree
new-parse) (.setOldTree (.diff git-r) old-parse)
(PathFilter/create file-path)) new-parse)
out))) (PathFilter/create file-path))
(.toString out)))) out))))
(.toString out))))
(defn fetch-version (defn fetch-version

View file

@ -4,7 +4,6 @@
smeagol.layout smeagol.layout
(:require [selmer.parser :as parser] (:require [selmer.parser :as parser]
[clojure.string :as s] [clojure.string :as s]
[noir.io :as io]
[ring.util.response :refer [content-type response]] [ring.util.response :refer [content-type response]]
[compojure.response :refer [Renderable]] [compojure.response :refer [Renderable]]
[environ.core :refer [env]] [environ.core :refer [env]]

View file

@ -2,7 +2,6 @@
:author "Simon Brooke"} :author "Simon Brooke"}
smeagol.middleware smeagol.middleware
(:require [taoensso.timbre :as timbre] (:require [taoensso.timbre :as timbre]
[selmer.parser :as parser]
[environ.core :refer [env]] [environ.core :refer [env]]
[selmer.middleware :refer [wrap-error-page]] [selmer.middleware :refer [wrap-error-page]]
[prone.middleware :refer [wrap-exceptions]] [prone.middleware :refer [wrap-exceptions]]

View file

@ -62,7 +62,7 @@
"Put an individual user's details on screen for editing." "Put an individual user's details on screen for editing."
[request] [request]
(let [params (keywordize-keys (:params request)) (let [params (keywordize-keys (:params request))
target (:target params) target (or (:target params) "")
pass1 (:pass1 params) pass1 (:pass1 params)
password (if (and pass1 (auth/evaluate-password pass1 (:pass2 params))) pass1) password (if (and pass1 (auth/evaluate-password pass1 (:pass2 params))) pass1)
stored (if (:email params) stored (if (:email params)

View file

@ -7,7 +7,6 @@
[cemerick.url :refer (url url-encode url-decode)] [cemerick.url :refer (url url-encode url-decode)]
[compojure.core :refer :all] [compojure.core :refer :all]
[clj-jgit.porcelain :as git] [clj-jgit.porcelain :as git]
[markdown.core :as md]
[noir.io :as io] [noir.io :as io]
[noir.response :as response] [noir.response :as response]
[noir.util.route :as route] [noir.util.route :as route]

View file

@ -2,9 +2,9 @@
:author "Simon Brooke"} :author "Simon Brooke"}
smeagol.util smeagol.util
(:require [noir.session :as session] (:require [noir.session :as session]
[clojure.java.io :as cljio]
[noir.io :as io] [noir.io :as io]
[scot.weft.i18n.core :as i18n] [scot.weft.i18n.core :as i18n]
[taoensso.timbre :as timbre]
[smeagol.authenticate :as auth] [smeagol.authenticate :as auth]
[smeagol.configuration :refer [config]] [smeagol.configuration :refer [config]]
[smeagol.formatting :refer [md->html]])) [smeagol.formatting :refer [md->html]]))
@ -51,7 +51,7 @@
(merge (merge
(i18n/get-messages (i18n/get-messages
((:headers request) "accept-language") ((:headers request) "accept-language")
(str (io/resource-path) "../i18n") (.getAbsolutePath (cljio/file (io/resource-path) ".." "i18n"))
"en-GB") "en-GB")
config)) config))

View file

@ -1,7 +1,6 @@
(ns smeagol.test.diff2html (ns smeagol.test.diff2html
(:use clojure.test (:require [clojure.test :refer :all]
ring.mock.request [smeagol.diff2html :refer :all]))
smeagol.diff2html))
(deftest test-mung-line (deftest test-mung-line
(testing "conversion of individual lines" (testing "conversion of individual lines"

View file

@ -1,7 +1,6 @@
(ns smeagol.test.util (ns smeagol.test.formatting
(:use clojure.test (:require [clojure.test :refer :all]
ring.mock.request [smeagol.formatting :refer [local-links no-text-error]]))
smeagol.formatting))
(deftest test-local-links (deftest test-local-links
(testing "Rewriting of local links" (testing "Rewriting of local links"

View file

@ -1,13 +1,13 @@
(ns smeagol.test.handler (ns smeagol.test.handler
(:use clojure.test (:require [clojure.test :refer :all]
ring.mock.request [ring.mock.request :refer :all]
smeagol.handler)) [smeagol.handler :refer :all]))
(deftest test-app (deftest test-app
(testing "main route" (testing "main route"
(let [response (app (request :get "/"))] (let [response (app (request :get "/" {:accept-language "en-GB"}))]
(is (= 200 (:status response))))) (is (= 200 (:status response)))))
(testing "not-found route" (testing "not-found route"
(let [response (app (request :get "/invalid"))] (let [response (app (request :get "/invalid" {:accept-language "en-GB"}))]
(is (= 404 (:status response)))))) (is (= 404 (:status response))))))