Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 115 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,115 @@
# BlogWithFirebase
## 🌟 Blog Application with Firebase

A dynamic and user-friendly **Blog Application** built with modern web technologies. This platform enables users to create, manage, and explore engaging blog posts, offering seamless functionality and an elegant design. Currently Blogs can be uploaded by Admins only while Users can view and comment on the blogs.

---

## 🖥️ Features

- **User-Friendly Interface**: Intuitive and responsive design for all devices.
- **Authentication**:
- Login/Logout functionality.
- Role-based access (Admin/User).
- **Blog Management**:
- Create, update, and delete blog posts.
- Display blogs with proper formatting and conditional image rendering.
- **Dashboard**:
- Lists all blogs with titles, authors, excerpts, and "Read More" links.
- Automatically handles anonymous users and login prompts.
- **15+ Categories to Upload Blogs**
- **Searching & Sorting Feature (Latest, Oldest, Most Viewed)**
- **User Comments & View Count**
- **Thymeleaf Integration**:
- Dynamic server-side rendering with Thymeleaf.
- **Secure Access**:
- Authorization checks ensure that only authenticated users can access certain pages.

---

## 🛠️ Tech Stack

- **Frontend**:
- HTML5, CSS3
- Thymeleaf (for server-side templating)
- Font Awesome (for icons)
- **Backend**:
- Java Spring Boot
- **Database**:
- MySQL
- **Build Tool**:
- Maven
- **Spring Security**

---

## 🚀 Installation and Setup

1. **Clone the Repository**:
```bash
git clone https://github.com/Programmer-govind/BlogWithFirebase.git
cd BlogWithFireBase
```

2. **Configure the Database**:
- Create a database in MySQL (e.g., `blog_app`).
- Update the database credentials in `application.properties`:
```properties
spring.datasource.url=jdbc:mysql://localhost:3306/blog_app
spring.datasource.username=your-username
spring.datasource.password=your-password
```

3. **Run the Application**:
```bash
mvn spring-boot:run
```

4. **Access the Application**:
Open your browser and navigate to:
```
http://localhost:9595
```

---

## 📸 Screenshots

### Dashboard
![Dashboard Screenshot](https://github.com/user-attachments/assets/b3d6de5a-9807-4cd0-adb4-76a877c283f5)

### User Profile
![User Profile](https://github.com/user-attachments/assets/208daf01-2a33-43c9-80ea-29ba2de5046b)


### Blog Management
![Blog Management Screenshot](https://github.com/user-attachments/assets/71a12767-ad7a-4a90-bc30-c3dfc178da2d)


---

## 🤝 Contributing

Contributions are welcome! If you'd like to contribute, please:
1. Fork the repository.
2. Create a feature branch:
```bash
git checkout -b feature/your-feature
```
3. Commit your changes:
```bash
git commit -m "Add your feature"
```
4. Push to your branch:
```bash
git push origin feature/your-feature
```
5. Create a pull request.

---

## ✨ Acknowledgments

- Thanks to **Spring Boot** for making backend development smooth and efficient.
- Inspired by modern blogging platforms to provide an elegant user experience.

---
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.deleteCookies("JSESSIONID")
.permitAll()
);
return http.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import java.security.Principal;

import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.ResponseStatusException;

import com.example.LoginPlusSecurity.model.BlogPost;
import com.example.LoginPlusSecurity.repository.BlogPostRepository;
Expand All @@ -25,93 +27,111 @@ public class BlogPostController {
private final BlogPostRepository blogPostRepository;
private final CommentRepository commentRepository;

public BlogPostController(BlogPostService blogPostService,
CategoryRepository categoryRepository,
BlogPostRepository blogPostRepository,
CommentRepository commentRepository) {

public BlogPostController(BlogPostService blogPostService, CategoryRepository categoryRepository, BlogPostRepository blogPostRepository, CommentRepository commentRepository) {
this.blogPostService = blogPostService;
this.categoryRepository = categoryRepository;
this.blogPostRepository = blogPostRepository;
this.commentRepository = commentRepository;
}


@GetMapping("/admin/manage")
public String home() {
return "manage";
}

@GetMapping("/")
public String showHomePage(@RequestParam(defaultValue = "latest") String filter,
@RequestParam(defaultValue = "0") int page,
Model model) {
return paginateAndRenderHomePage(blogPostService.homepageSorting(page, 5, filter), filter, page, model, "home");
}

@GetMapping("/search")
public String searchBlogPosts(@RequestParam String query,
@RequestParam(defaultValue = "latest") String filter,
@RequestParam(defaultValue = "0") int page,
Model model) {
Page<BlogPost> blogPosts = blogPostService.titleSorting(query, page, 5, filter); // Reuse service method

int size = 5;
Page<BlogPost> blogPosts = blogPostService.homepageSorting(page, size, filter);
model.addAttribute("blogPosts", blogPosts.getContent());
model.addAttribute("categories", categoryRepository.findAll());
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", blogPosts.getTotalPages());
model.addAttribute("query", query); // Ensure query is passed to the template
model.addAttribute("filter", filter); // Ensure filter is passed for UI consistency
return "searchResults"; // Consistent with other endpoints
model.addAttribute("filter", filter);
return "home";
}


@GetMapping("/search")
public String searchBlogPosts(@RequestParam("query") String query,
@RequestParam(defaultValue = "latest") String filter,
@RequestParam(defaultValue = "0") int page,
Model model) {
int size = 5; // Fixed size
Page<BlogPost> blogPosts = blogPostService.titleSorting(query, page, size, filter);
model.addAttribute("blogPosts", blogPosts.getContent());
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", blogPosts.getTotalPages());
model.addAttribute("query", query);
model.addAttribute("filter", filter);
return "searchResults";
}


@GetMapping("/category/{id}")
public String getBlogPostsByCategory(@PathVariable("id") Long categoryId,
@RequestParam(defaultValue = "latest") String filter,
@RequestParam(defaultValue = "0") int page,
Model model) {
Page<BlogPost> blogPosts = blogPostService.categorySorting(categoryId, page, 5, filter);
String categoryName = categoryRepository.getCategoryNameById(categoryId);
model.addAttribute("categoryName", categoryName);
@RequestParam(defaultValue = "latest") String filter,
@RequestParam(defaultValue = "0") int page,
Model model) {
int size = 5; // Fixed size
Page<BlogPost> blogPosts = blogPostService.categorySorting(categoryId, page, size, filter);
String categoryName = categoryRepository.getCategoryNameById(categoryId); // Fetch category name
model.addAttribute("blogPosts", blogPosts.getContent());
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", blogPosts.getTotalPages());
model.addAttribute("filterCategoryId", categoryId);
return paginateAndRenderHomePage(blogPosts, filter, page, model, "categoryResults");
model.addAttribute("categoryName", categoryName); // Add category name to the model
model.addAttribute("filter", filter);
return "categoryResults";
}



@GetMapping("/page/{pageNumber}")
public String showPaginatedHomePage(@PathVariable int pageNumber,
@RequestParam(defaultValue = "latest") String sortBy,
@ModelAttribute("sortBy") String sortBy,
Model model) {
return paginateAndRenderHomePage(blogPostService.homepageSorting(pageNumber, 5, sortBy), sortBy, pageNumber, model, "home");
int size = 5;
Page<BlogPost> blogPosts = blogPostService.homepageSorting(pageNumber, size, sortBy);
model.addAttribute("blogPosts", blogPosts.getContent());
model.addAttribute("currentPage", pageNumber);
model.addAttribute("totalPages", blogPosts.getTotalPages());
model.addAttribute("sortBy", sortBy);
return "home";
}


@GetMapping("/blog/{slug}")
public String viewBlogPost(@PathVariable String slug, Model model) {
BlogPost blogPost = blogPostService.findBySlug(slug);
blogPost.setViews(blogPost.getViews() + 1);
blogPostRepository.save(blogPost); // Update view count
model.addAttribute("blogPost", blogPost);
model.addAttribute("comments", commentRepository.findByBlogPostId(blogPost.getId()));
return "viewBlog";
try {
BlogPost blogPost = blogPostService.findBySlug(slug);
blogPost.setViews(blogPost.getViews() + 1);
blogPostRepository.save(blogPost); // Save updated view count
model.addAttribute("blogPost", blogPost);
model.addAttribute("comments", commentRepository.findByBlogPostId(blogPost.getId()));
return "viewBlog";
} catch (RuntimeException e) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
}
}


@GetMapping("/admin/blog/create")
public String showCreateBlogForm(Model model) {
model.addAttribute("blogPost", new BlogPost());
model.addAttribute("categories", categoryRepository.findAll());
return "createBlog";
}


@PostMapping("/admin/blog/create")
public String createBlogPost(@ModelAttribute BlogPost blogPost, Principal principal) {
blogPost.setAuthorName(principal.getName()); // Set logged-in user's name
blogPost.setAuthorName(principal.getName()); // Fetch the logged-in user's name
blogPostService.saveBlogPost(blogPost);
return "redirect:/";
}

// Helper method for pagination setup
private String paginateAndRenderHomePage(Page<BlogPost> blogPosts, String filter, int page, Model model, String viewName) {
model.addAttribute("blogPosts", blogPosts.getContent());
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", blogPosts.getTotalPages());
model.addAttribute("categories", categoryRepository.findAll());
model.addAttribute("filter", filter);
return viewName;
return "redirect:/"; //
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ public String getUserDetails(@PathVariable String username, Model model) {
if (user.isPresent()) {
model.addAttribute("user", user.get());
return "user-details";
} else {
}
else {
model.addAttribute("error", "User not found");
return "error";
}
}
// @GetMapping("")
// public String userProfile() {
//
// }
}
Loading