How to create a blog project

Keywords: Programming Database git github MySQL

1. First pull the skeleton project as the basis, and the file is named myprogect.

git clone https://github.com/huntlabs/hunt-skeleton.git myproject
cd myproject
dub run -v

2. Modify the database configuration in the application.conf file under congig in the project

hunt.database.default.driver=mysql
hunt.database.default.host=127.0.0.1
hunt.database.default.port=3306  //Interface
hunt.database.default.database=myblog //Database name
hunt.database.default.username=root //Database username
hunt.database.default.password=     //Database password
hunt.database.default.charset=utf8  
hunt.database.default.prefix=
hunt.database.default.enabled=true  

3. First, implement the background management of Blog project; determine the background function of the project and create admin.routes file to define routing under config

GET /user/list user.users //User List Page

*  /user/add  user.add   //User add operation

GET  /user/delete  user.remove  //User Delete Operation

GET  /user/update  user.update  //User Modification Page

POST  /user/doup  user.doupdate  //User modification operation

GET /blog/list blog.blogs   //Article List Page

* /blog/add blog.add    //Article Add Page

POST /blog/doadd/ blog/doadd  //Article Addition Operation

4. Blog module is built under source-app, model model is built in Blog, Blog.d and User.d files are created under model to store data in corresponding data tables.

//Blog.d
module app.blog.model.Blog;                     
import hunt.entity;
import app.model.User;

@Table("blog")
class Blog : Model
{
    mixin MakeModel;

    @AutoIncrement
    @PrimaryKey
    int id; //Primary key, automatic growth

    long created;  //time
    
    string title;  //Title of article
    
    string description;  //describe
  
    string picture;  //picture

    string  content; //content
    
    @OneToOne()
    @JoinColumn("user_id")
    User  user;//Associate User tables with user_id
}

//User.d
module app.blog.model.User;
import hunt.entity;

@Table("user")
class User : Model 
{
    mixin  MakeModel;

    @AutoIncrement
    @PrimaryKey
    int id;

    string username;  //User name

    string password;  //Password
    
    string email;  //mailbox
}

5. Based on model; create new repository file under source-app-blog, create corresponding BlogRepository.d and UserRepository.d files; operate data

//BlogRepository.d
module app.blog.repository.BlogRepository;
import app.blog.model.Blog; 

import hunt.entity;
class BlogRepository : EntityRepository!(Blog , int){
}

//UserRepository.d
module app.blog.repository.UserRepository;
import app.blog.model.User; 

import hunt.entity;
class UserRepository : EntityRepository!(User,int){
}

6. Create new admin file under source-app-blog, create BlogController.d and UserController.d in admin to realize background management, including article management and browsing, adding, deleting and modifying users.

//BlogController.d
module app.blog.controller.admin.BlogController;
import hunt.framework;
import app.blog.form.BlogForm;
import app.blog.model.Blog;
import app.blog.repository.BlogRepository;
import app.blog.repository.UserRepository;

class BlogController : Controller
{
    mixin MakeController;
    
    //Addition of articles
    @Action
    string add(BlogForm form)
    {
        if(request.method == HttpMethod.POST)
        {
            auto result = form.valid();
            if(result.isValid)
            {
                auto blog = new Blog ;
                blog.title = form.tit;
                
                blog.description = form.dept;
                blog.picture = form.pic;
                blog.content = form.cont;
                blog.created = time();
                
                auto repo = new BlogRepository;
                repo.save(blog);

                return "successed!";
            }
            view.assign("messages", result.messages());
        }
        view.assign("blog", (form is null) ? new BlogForm : form);
        view.assign("users", (new UserRepository).findAll());//Find out all the information about User

        return view.render("blog_add");
    }
    
    //Browse List of Articles
    @Action
    string  blogs()
    {
        auto repo = new BlogRepository;

        auto blogs = repo.findAll();//Find all article information

        view.assign("blogs",blogs);

        return view.render("blog_list");//Jump to the list page
    }
}
//UserController.d
module app.blog.controller.admin.UserController;
import hunt.framework;
import app.blog.form.UserForm;
import app.blog.model.User;
import app.blog.repository.UserRepository;

class UserController : Controller
{
    mixin MakeController;
    
    //User additions
    @Action
    string add(UserForm form)
    {
        if (request.method == HttpMethod.POST)
        {
            auto result = form.valid();
            if(result.isValid)
            {
                auto user = new User;
                user.username = form.um;
                user.password = form.pwd;
                user.email = form.mail; 

                auto repo = new UserRepository;
                repo.save(user);

                 return "successed";
            }
            view.assign("messages",result.messages());
        } 
        view.assign("user",(form is null) ? new UserForm : form);
        return view.render("user_add");
    }

    //User List Browsing
    @Action
    string  users()
    {
        auto repo = new UserRepository;

        auto users = repo.findAll();

        view.assign("users",users);

        return view.render("user_list");
    }
    
    //User Delete Operation
    @Action
    string remove(int id)
    {
        auto repo = new UserRepository;

        repo.removeById(id);//Delete user information based on id

        return "deleted";
    }
    
    //User Modification List
    @Action
    string update(int id)
    {
        auto repo = new UserRepository;

        auto user = repo.find(id);//Find the information to be modified by id

        view.assign("user",user);

        return view.render("user_up");//Jump to the Modification Page
    }
    //User modification operation
    @Action
    string doupdate(UserForm form)
    {
        auto repo = new UserRepository;
        auto user = repo.find(form.id.to!int);

        user.username = form.um;
        user.password = form.pwd;
        user.email = form.mail;//Modification
        repo.save(user);//Preservation

        return "successed";
    }
}

7. Create admin under view, and create CSS style of header.html, footer.html, sidebar.html display list and directory in admin; blog_list.html, blog_add.html, user_add.html, user_list.html, user_up.html to realize function list; Display part code;

//blog_list.html
<div class="card-body">
      <table id="example2" class="table table-bordered table-hover">
        <thead>
        <tr>
          <th>title</th>
          <th>name</th> 
          <th>description</th>
          <th>picture</th>
          <th>content</th>
          
        </tr>
        </thead>
        {% for blog in blogs %}
        <tbody>
        <tr>
          <td>{{ blog.title }}</td>
          <td>{{ blog.user.username}}</td>
          <td>{{ blog.description }}</td>
          <td>{{ blog.picture }}</td>
          <td>{{ blog.content }}  <a href="/admincp/blog/view?id={{ blog.id }}">Read Full</a></td>
      
        </tr>
        </tbody>
        {% endfor %}
    
        <tfoot>
        <tr>
            <th>title</th>
            <th>name</th>
            <th>description</th>
            <th>picture</th>
            <th>content</th>
          
        </tr>
        </tfoot>
      </table>
</div>
//blog_add.html
<form role="form"  method="POST" action="/admincp/blog/add">
    <div class="card-body">
    {% if messages %}
    <div class="form-group">
      <ul>
        {% for key, message in messages %}
        <li>{{ key }} : {{ message }}</li>
        {% endfor %}
      </ul>
    </div>
    {% endif %}

    <div class="form-group">
        <label for="exampleInputPassword1">title</label>
         <input type="text" name="tit"  value="{{blog.tit}}" class="form-control" id="exampleInputPassword1" placeholder="title">
    </div>

      <div class="form-group">
        <label for="exampleInputEmail1">name</label>
        <select name="nm">
          <option value="0">-- Please choose --</option>
          {% for user in users %}
            <option value="{{ user.id }}" {% if blog.nm %}{% if user.id == int(blog.nm) %} selected {% endif %}{% endif %}>{{ user.username }}</option>
          {% endfor %}
        </select>
      </div>
      
      <div class="form-group">
        <label for="exampleInputEmail1">description</label>
        <input type="text" name="dept" value="{{blog.dept}}"  class="form-control" id="exampleInputEmail1" placeholder="description">
      </div>

      <div class="form-group">
        <label for="exampleInputEmail1">picture</label>
        <input type="text" name="pic" class="form-control" id="exampleInputEmail1" placeholder="picture">
      </div>

      <div class="form-group">
        <label for="exampleInputEmail1">content</label>
        <input type="text" name="cont" value="{{blog.cont}}"  class="form-control" id="exampleInputEmail1" placeholder="content">
      </div>

    </div>
    <!-- /.card-body -->

    <div class="card-footer">
      <button type="submit" class="btn btn-primary"></a>Adding articles</button>
    </div>
</form>
//user_add.html
</div>
  <form role="form" method="POST" action="/admincp/user/add">
    <div class="card-body">
      {% if messages %}
        <div class="form-group">
          <ul>
            {% for key, message in messages %}
            <li>{{ key }} : {{ message }} </li>
            {% endfor %}
          </ul>
        </div>
        {% endif %}

        <div class="form-group">
          <label for="exampleInputEmail1">Username</label>
          <input type="text"  name="um" value="{{user.um}}" class="form-control" id="exampleInputEmail1" placeholder="username">
        </div>
        <div class="form-group">
          <label for="exampleInputPassword1">Password</label>
          <input type="password" name="pwd" value="{{user.pwd}}"  class="form-control" id="exampleInputPassword1" placeholder="password">
        </div>
        <div class="form-group">
          <label for="exampleInputEmail1">Email address</label>
          <input type="text" name="mail" value="{{user.mail}}" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
        </div>
    </div>
    <!-- /.card-body -->

    <div class="card-footer">
      <button type="submit" class="btn btn-primary">Adding users</button>
    </div>
  </form>
</div>
//user_list.html
<div class="card-body">
  <table id="example2" class="table table-bordered table-hover">
    <thead>
    <tr>
      <th>username</th>
      <th>email</th>
      <th>Delete</th>
      <th>Update</th>
    </tr>
    </thead>
    {% for user in users %}
    <tbody>
    <tr>
      <td>{{ user.username}}</td>
      <td>{{ user.email}}</td>
      <td><a href="/admincp/user/delete?id={{ user.id }}">Delete</a></td>
      <td><a href="/admincp/user/update?id={{ user.id }}">Update</a></td>
    </tr>
    </tbody>
    {% endfor %}

    <tfoot>
    <tr>
      <th>username</th>
      <th>email</th>
      <th>Delete</th>
      <th>Update</th>
    </tr>
    </tfoot>
  </table>
</div>
//user_up.html
<form method="POST" action="/admincp/user/doup">
    <input name="id" type="hidden" value="{{ user.id }}">
    <p>Username:<input name="um" type="text" value="{{ user.username }}"></p>
    <p>Password:<input name="pwd" type="password" value="{{ user.password }}"></p>
    <p>Email:<input name="mail" type="text" value="{{ user.email }}"></p>
    <p> <button type="submit" value="Update"></button></p>
</form>

8. Create new form file under source-app-blog, create form form form BlogForm.d, UserForm.d files, match the field value of name in template page, and define the scope of field;

//BlogForm.d
module app.blog.form.BlogForm;
import hunt.framework;

class BlogForm : Form
{
    mixin MakeForm;

    string id; 

    string uid; //user_id associated with User table

    @NotEmpty  //The value of name cannot be empty
    string nm;

    @Length(6,18)  //The value of title is between 6 and 18 bits.
    string tit;

    @Length(10,100) //The value of description is between 10 and 100 bits.
    string dept;

    string pic; //picture

    @Length(10,200) //The value of content is between 10 and 200 bits.
    string cont;
}
//UserForm.d
module app.blog.form.UserForm;
import hunt.framework;

class UserForm : Form
{
    mixin MakeForm;
    
    string id;
    
    @Length(3, 18) //User name values range from 3 to 18 bits
    string um;

    @Length(6, 16) //The value of the password is between 6 and 16 bits.
    string pwd;

    @Length(6, 32) //The value of the mailbox is between 6 and 32 bits.
    string mail;
}

9. Conduct the front-end management of Blog project; determine the functions that the front-end can achieve, and define routing in routes under config

GET   /add  blog.add  //Article Add Page

POST  /blog/add  blog.doadd  //Article Addition Operation

GET   /blog/delete  blog.remove  //Article deletion operation

GET  /blog/list   blog.blogs  //Articles List Browse Page

POST  /blog/doup  blog.doupdate  //Article modification operation

GET  /blog/update   blog.update  //Article Modification Page

10. Create BlogController.d file under source-app-controller to realize Blog foreground management including browsing, adding, modifying and deleting functions.

module app.blog.controller.BlogController;
import app.blog.form.BlogForm;
import app.blog.model.Blog;
import app.blog.repository.BlogRepository;
import hunt.framework;

class BlogController : Controller
{
    mixin MakeController;
    //Article Addition
    @Action
    string add()//Jump to Add Page Add
    {
        return view.render("blog_add");
    }
    @Action
    string doadd(BlogForm form)//Adding operations
    {
        auto blog = new Blog ;
        blog.title = form.tit;
        blog.description = form.dept;
        blog.picture = form.pic;
        blog.content = form.cont;
        blog.created = time();//Time is the current time

        auto repo = new BlogRepository;
        repo.save(blog);//Preservation

        return "successed!";
    }
    //List of articles
    @Action
    string  blogs()
    {
        auto repo = new BlogRepository;

        auto blogs = repo.findAll();//Find all article information

        view.assign("blogs",blogs);

        return view.render("blog_list");//Jump to the list page
    }
    //Article deletion
    @Action
    string remove(int id)
    {
        auto repo = new BlogRepository;

        repo.removeById(id);//Delete article information by id

        return "deleted";
    }
    //Article revision
    @Action
    string update(int id)//Modify the page
    {
        auto repo = new BlogRepository;

        auto blog = repo.find(id);//Find the article information that needs to be modified by id

        view.assign("blog",blog);

        return view.render("blog_up");//Jump to the Modification Page
    }

    @Action
    string doupdate(BlogForm form)//Modification operation
    {
        auto repo = new BlogRepository;
        auto blog = repo.find(form.id.to!int);

        blog.title = form.tit;
        blog.description = form.dept;
        blog.picture = form.pic;
        blog.content = form.cont;//Modification

        repo.save(blog);//Preservation
        return "successed";
    }
}

11. Create footer. HTML in default under views, header. html is used to store CSS styles in template pages, blog_add.html, blog_up.html and blog_list.html show blog addition, modification and list template pages respectively.

//blog_list.html

{% include "header.html" %}
  <!-- Page Content -->
  <div class="container">

    <div class="row">

      <!-- Blog Entries Column -->
      <div class="col-md-8">

        <h1 class="my-4">Page Heading
          <small>Secondary Text</small>
        </h1>

        {% for blog in blogs %}
        <!-- Blog Post -->
        <div class="card mb-4">
          <img class="card-img-top" src="http://placehold.it/750x300" alt="Card image cap">
          <div class="card-body">
            <h2 class="card-title">{{blog.title}}</h2>
            <p class="card-text">{{blog.description}}</p>
            <a href="/blog/view?id={{blog.id}}" class="btn btn-primary">Read More &rarr;</a>
          </div>
          <div class="card-footer text-muted">
            Posted on {{ date("m-d H:i:s",blog.created)}}
            <a href="#">{{blog.user.username}}</a>
          </div>
        </div>
        {% endfor %}
{% include "footer.html" %}
//blog_add.html
<html>
    <body>
        <form method="POST" action="/blog/add">
            <p>Name:<input name="nm" type="text"></p>
            <p>Title:<input name="tit" type="text"></p>
            <p>Description: <input name="dept" type="text"></p>
            <p>Picture: <input name="pic" type="text"></p>
            <p>Content: <input name="cont" type="text"></p>
            <p><button type="submit" value="Add"></button></p>
        </form>
    </body>
</html>

//blog_up.html
<form method="POST" action="/blog/doup">
    <input name="id" type="hidden" value="{{blog.id}}">
    <p>Name:<input name="nm" type="text" value="{{ blog.name }}"></p>
    <p>Title:<input name="tit" type="text" value="{{ blog.title }}"></p>
    <p>Description: <input name="dept" type="text" value="{{ blog.description }}"></p>
    <p>Picture: <input name="pic" type="text" value="{{ blog.picture }}"></p>
    <p>Content: <input name="cont" type="text" value="{{ blog.content }}"></p>
    <p><button type="submit" value="Update"></button></p>
</form>

Posted by rich___ on Thu, 29 Aug 2019 21:05:55 -0700