← back to inzamulhaque1__my-blog

Function bodies 345 total

All specs Real LLM only Function bodies
resetSuperAdmin function · typescript · L45-L87 (43 LOC)
scripts/reset-super-admin.ts
async function resetSuperAdmin() {
  try {
    console.log('Connecting to MongoDB...');
    await mongoose.connect(MONGODB_URI);
    console.log('Connected to MongoDB');

    const SuperAdmin = mongoose.models.SuperAdmin || mongoose.model('SuperAdmin', SuperAdminSchema);

    // Delete existing super admin
    const deleted = await SuperAdmin.deleteOne({ email: SUPER_ADMIN_EMAIL.toLowerCase() });
    if (deleted.deletedCount > 0) {
      console.log('Deleted existing super admin');
    }

    // Hash password
    const salt = await bcrypt.genSalt(12);
    const hashedPassword = await bcrypt.hash(SUPER_ADMIN_PASSWORD, salt);

    // Create new super admin
    await SuperAdmin.create({
      name: SUPER_ADMIN_NAME,
      email: SUPER_ADMIN_EMAIL.toLowerCase(),
      password: hashedPassword,
      role: 'super_admin',
      permissions: [],
      isActive: true,
    });

    console.log('\nSuper Admin reset successfully!');
    console.log('─'.repeat(50));
    console.log('Email:', SUPER
seedPlans function · typescript · L145-L179 (35 LOC)
scripts/seed-plans.ts
async function seedPlans() {
  try {
    console.log('Connecting to MongoDB...');
    await mongoose.connect(MONGODB_URI);
    console.log('Connected to MongoDB');

    const Plan = mongoose.models.Plan || mongoose.model('Plan', PlanSchema);

    for (const planData of defaultPlans) {
      const existing = await Plan.findOne({ slug: planData.slug });

      if (existing) {
        console.log(`Plan "${planData.name}" already exists, updating...`);
        await Plan.updateOne({ slug: planData.slug }, planData);
      } else {
        await Plan.create(planData);
        console.log(`Created plan: ${planData.name}`);
      }
    }

    console.log('\n✅ Plans seeded successfully!');
    console.log('\nAvailable plans:');
    console.log('─'.repeat(50));
    for (const plan of defaultPlans) {
      console.log(`  ${plan.name}: $${plan.price.monthly}/mo - ${plan.limits.maxPosts === -1 ? 'Unlimited' : plan.limits.maxPosts} posts`);
    }

  } catch (error) {
    console.error('Error seedin
seedSuperAdmin function · typescript · L45-L91 (47 LOC)
scripts/seed-super-admin.ts
async function seedSuperAdmin() {
  try {
    console.log('Connecting to MongoDB...');
    await mongoose.connect(MONGODB_URI);
    console.log('Connected to MongoDB');

    const SuperAdmin = mongoose.models.SuperAdmin || mongoose.model('SuperAdmin', SuperAdminSchema);

    // Check if super admin already exists
    const existing = await SuperAdmin.findOne({ email: SUPER_ADMIN_EMAIL.toLowerCase() });

    if (existing) {
      console.log('Super admin already exists with email:', SUPER_ADMIN_EMAIL);
      console.log('If you need to reset the password, delete the existing admin first.');
      process.exit(0);
    }

    // Hash password
    const salt = await bcrypt.genSalt(12);
    const hashedPassword = await bcrypt.hash(SUPER_ADMIN_PASSWORD, salt);

    // Create super admin
    const admin = await SuperAdmin.create({
      name: SUPER_ADMIN_NAME,
      email: SUPER_ADMIN_EMAIL.toLowerCase(),
      password: hashedPassword,
      role: 'super_admin',
      permissions: [], // sup
AboutPage function · typescript · L13-L133 (121 LOC)
src/app/about/page.tsx
export default async function AboutPage() {
  const authors = await getAllAuthors();

  return (
    <div className="container mx-auto px-4 py-12">
      <div className="mx-auto max-w-4xl">
        {/* Hero */}
        <div className="mb-16 text-center">
          <h1 className="mb-4 text-4xl font-bold text-gray-900 dark:text-white md:text-5xl">
            About {siteConfig.name}
          </h1>
          <p className="text-xl text-gray-600 dark:text-gray-400">
            {siteConfig.description}
          </p>
        </div>

        {/* Mission */}
        <section className="mb-16">
          <h2 className="mb-6 text-2xl font-bold text-gray-900 dark:text-white">
            Our Mission
          </h2>
          <div className="prose prose-lg max-w-none dark:prose-invert">
            <p className="text-gray-700 dark:text-gray-300">
              We believe in sharing knowledge and helping developers grow. Our mission is to
              provide high-quality, practical content that
fetchAuthor function · typescript · L37-L68 (32 LOC)
src/app/admin/authors/[id]/edit/page.tsx
    async function fetchAuthor() {
      try {
        const response = await fetch(`/api/admin/authors/${id}`);
        const data = await response.json();

        if (!response.ok) {
          throw new Error(data.error || 'Failed to fetch author');
        }

        const author = data.data;
        setFormData({
          name: author.name || '',
          email: author.email || '',
          password: '', // Don't show existing password
          avatar: author.avatar || '',
          bio: author.bio || '',
          role: author.role || 'Author',
          canLogin: author.canLogin || false,
          canPost: author.canPost || false,
          social: {
            twitter: author.social?.twitter || '',
            github: author.social?.github || '',
            linkedin: author.social?.linkedin || '',
            website: author.social?.website || '',
          },
        });
      } catch (err: any) {
        setError(err.message);
      } finally {
        setFetching(fals
NewAuthorPage function · typescript · L8-L320 (313 LOC)
src/app/admin/authors/new/page.tsx
export default function NewAuthorPage() {
  const router = useRouter();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [showPassword, setShowPassword] = useState(false);

  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    avatar: '',
    bio: '',
    role: 'Author',
    canLogin: false,
    canPost: false,
    social: {
      twitter: '',
      github: '',
      linkedin: '',
      website: '',
    },
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError('');

    // Validate password if canLogin is enabled
    if (formData.canLogin && !formData.password) {
      setError('Password is required when login is enabled');
      setLoading(false);
      return;
    }

    if (formData.password && formData.password.length < 6) {
      setError('Password must be at least 6 characters');
      setLoading(false);
      return;
    }
getValidImageSrc function · typescript · L12-L18 (7 LOC)
src/app/admin/authors/page.tsx
function getValidImageSrc(image: string | undefined | null): string {
  if (!image) return DEFAULT_AVATAR;
  if (image.startsWith('/') || image.startsWith('http://') || image.startsWith('https://')) {
    return image;
  }
  return DEFAULT_AVATAR;
}
Repobility · severity-and-effort ranking · https://repobility.com
getAuthors function · typescript · L20-L48 (29 LOC)
src/app/admin/authors/page.tsx
async function getAuthors(tenantId?: string) {
  await connectDB();

  // Build filter with tenant isolation
  const filter: any = {};
  if (tenantId) {
    filter.tenantId = tenantId;
  }

  const authors = await Author.find(filter).sort({ createdAt: -1 }).lean();

  // Get post count for each author
  const authorsWithPostCount = await Promise.all(
    authors.map(async (author: any) => {
      const postFilter: any = { author: author._id };
      if (tenantId) {
        postFilter.tenantId = tenantId;
      }
      const postCount = await Post.countDocuments(postFilter);
      return {
        ...author,
        _id: author._id.toString(),
        postCount,
      };
    })
  );

  return authorsWithPostCount;
}
AdminAuthorsPage function · typescript · L50-L120 (71 LOC)
src/app/admin/authors/page.tsx
export default async function AdminAuthorsPage() {
  const session = await getServerSession(authOptions);
  const tenantId = session?.user?.tenantId;
  const authors = await getAuthors(tenantId);

  return (
    <div>
      <div className="mb-8 flex items-center justify-between">
        <h1 className="text-2xl font-bold text-gray-900 dark:text-white">Authors</h1>
        <Link
          href="/admin/authors/new"
          className="flex items-center gap-2 rounded-lg bg-primary-600 px-4 py-2 text-sm font-medium text-white hover:bg-primary-700"
        >
          <Plus className="h-4 w-4" />
          New Author
        </Link>
      </div>

      <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
        {authors.length === 0 ? (
          <div className="col-span-full rounded-xl bg-white p-12 text-center shadow-sm dark:bg-gray-800">
            <p className="text-gray-500">No authors yet. Create your first author!</p>
          </div>
        ) : (
          authors.map((aut
AdminLayoutContent function · typescript · L22-L256 (235 LOC)
src/app/admin/layout.tsx
function AdminLayoutContent({ children }: { children: React.ReactNode }) {
  const { data: session, status } = useSession();
  const router = useRouter();
  const pathname = usePathname();
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [tenantSlug, setTenantSlug] = useState<string | null>(null);
  const [redirecting, setRedirecting] = useState(false);

  const isAdmin = session?.user?.role === 'admin';
  const isEditor = session?.user?.role === 'editor';
  const isAuthor = session?.user?.role === 'author';
  const canPost = session?.user?.canPost;
  const userTenantId = session?.user?.tenantId;

  // Fetch tenant slug for redirect
  useEffect(() => {
    if (userTenantId && !tenantSlug) {
      fetch('/api/user/tenant')
        .then(res => res.json())
        .then(data => {
          if (data.success && data.data?.slug) {
            setTenantSlug(data.data.slug);
          }
        })
        .catch(console.error);
    }
  }, [userTenantId, tenantSlug]);

  useEff
AdminLayout function · typescript · L258-L264 (7 LOC)
src/app/admin/layout.tsx
export default function AdminLayout({ children }: { children: React.ReactNode }) {
  return (
    <SessionProvider>
      <AdminLayoutContent>{children}</AdminLayoutContent>
    </SessionProvider>
  );
}
AdminLoginContent function · typescript · L9-L255 (247 LOC)
src/app/admin/login/page.tsx
function AdminLoginContent() {
  const { data: session, status } = useSession();
  const router = useRouter();
  const searchParams = useSearchParams();
  const [loginType, setLoginType] = useState<'admin' | 'author'>('author');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [showPassword, setShowPassword] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [showForgotPassword, setShowForgotPassword] = useState(false);

  // Get error from URL params
  const urlError = searchParams.get('error');

  useEffect(() => {
    if (session?.user?.role === 'admin' || session?.user?.role === 'editor' || session?.user?.role === 'author') {
      router.push('/admin');
    }
  }, [session, router]);

  const handleAuthorLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError('');

    try {
      const result = await signIn('credentials', {
LoadingFallback function · typescript · L257-L263 (7 LOC)
src/app/admin/login/page.tsx
function LoadingFallback() {
  return (
    <div className="flex min-h-screen items-center justify-center bg-gray-100 dark:bg-gray-900">
      <div className="h-8 w-8 animate-spin rounded-full border-4 border-primary-600 border-t-transparent" />
    </div>
  );
}
AdminLoginPage function · typescript · L265-L271 (7 LOC)
src/app/admin/login/page.tsx
export default function AdminLoginPage() {
  return (
    <Suspense fallback={<LoadingFallback />}>
      <AdminLoginContent />
    </Suspense>
  );
}
getStats function · typescript · L9-L50 (42 LOC)
src/app/admin/page.tsx
async function getStats(authorId?: string, tenantId?: string) {
  await connectDB();

  // Build filter with tenant isolation
  const baseFilter: any = {};

  // CRITICAL: Always filter by tenantId for data isolation
  if (tenantId) {
    baseFilter.tenantId = tenantId;
  }

  // If authorId is provided, filter stats by that author
  if (authorId) {
    baseFilter.author = authorId;
  }

  const [totalPosts, publishedPosts, totalAuthors, totalViews] = await Promise.all([
    Post.countDocuments(baseFilter),
    Post.countDocuments({ ...baseFilter, published: true }),
    authorId ? 1 : Author.countDocuments(tenantId ? { tenantId } : {}),
    Post.aggregate([
      { $match: baseFilter },
      { $group: { _id: null, total: { $sum: '$views' } } },
    ]),
  ]);

  const recentPosts = await Post.find(baseFilter)
    .sort({ createdAt: -1 })
    .limit(5)
    .populate('author', 'name')
    .lean();

  return {
    totalPosts,
    publishedPosts,
    draftPosts: totalPosts - publishedPost
Open data scored by Repobility · https://repobility.com
AdminDashboard function · typescript · L52-L170 (119 LOC)
src/app/admin/page.tsx
export default async function AdminDashboard() {
  const session = await getServerSession(authOptions);

  // For authors, only show their own posts
  const isAuthor = session?.user?.role === 'author';
  const canPost = session?.user?.canPost;
  const authorId = isAuthor ? session?.user?.authorId : undefined;
  const tenantId = session?.user?.tenantId;

  const stats = await getStats(authorId, tenantId);

  // Build stat cards based on role
  const statCards = isAuthor
    ? [
        { label: 'Your Posts', value: stats.totalPosts, icon: FileText, color: 'bg-blue-500' },
        { label: 'Published', value: stats.publishedPosts, icon: TrendingUp, color: 'bg-green-500' },
        { label: 'Drafts', value: stats.draftPosts, icon: FileText, color: 'bg-yellow-500' },
        { label: 'Total Views', value: stats.totalViews, icon: Eye, color: 'bg-orange-500' },
      ]
    : [
        { label: 'Total Posts', value: stats.totalPosts, icon: FileText, color: 'bg-blue-500' },
        { label: 'P
getPost function · typescript · L13-L30 (18 LOC)
src/app/admin/posts/[id]/edit/page.tsx
async function getPost(id: string) {
  await connectDB();
  const post = await Post.findById(id).lean();
  if (!post) return null;

  return {
    id: (post as any)._id.toString(),
    title: (post as any).title,
    description: (post as any).description,
    content: (post as any).content,
    image: (post as any).image,
    category: (post as any).category,
    tags: (post as any).tags,
    author: (post as any).author.toString(),
    featured: (post as any).featured,
    published: (post as any).published,
  };
}
getAuthors function · typescript · L32-L39 (8 LOC)
src/app/admin/posts/[id]/edit/page.tsx
async function getAuthors() {
  await connectDB();
  const authors = await Author.find().lean();
  return authors.map((author: any) => ({
    id: author._id.toString(),
    name: author.name,
  }));
}
EditPostPage function · typescript · L41-L66 (26 LOC)
src/app/admin/posts/[id]/edit/page.tsx
export default async function EditPostPage({ params }: EditPostPageProps) {
  const session = await getServerSession(authOptions);
  const isAuthor = session?.user?.role === 'author';
  const authorId = isAuthor ? session?.user?.authorId : undefined;

  const { id } = await params;
  const [post, authors] = await Promise.all([getPost(id), getAuthors()]);

  if (!post) {
    notFound();
  }

  // Authors can only edit their own posts
  if (isAuthor && post.author !== authorId) {
    redirect('/admin/posts');
  }

  return (
    <div>
      <h1 className="mb-8 text-2xl font-bold text-gray-900 dark:text-white">
        Edit Post
      </h1>
      <PostForm authors={authors} initialData={post} fixedAuthorId={authorId} />
    </div>
  );
}
AdminPostsLoading function · typescript · L1-L59 (59 LOC)
src/app/admin/posts/loading.tsx
export default function AdminPostsLoading() {
  return (
    <div>
      <div className="mb-8 flex items-center justify-between">
        <div className="h-8 w-32 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
        <div className="h-10 w-28 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
      </div>

      <div className="rounded-xl bg-white shadow-sm dark:bg-gray-800">
        <div className="overflow-x-auto">
          <table className="w-full">
            <thead className="border-b bg-gray-50 dark:border-gray-700 dark:bg-gray-900">
              <tr>
                <th className="px-6 py-4 text-left text-sm font-medium text-gray-500">Title</th>
                <th className="px-6 py-4 text-left text-sm font-medium text-gray-500">Author</th>
                <th className="px-6 py-4 text-left text-sm font-medium text-gray-500">Category</th>
                <th className="px-6 py-4 text-left text-sm font-medium text-gray-500">Status</th>
                <th classNa
getAuthors function · typescript · L7-L14 (8 LOC)
src/app/admin/posts/new/page.tsx
async function getAuthors() {
  await connectDB();
  const authors = await Author.find().lean();
  return authors.map((author: any) => ({
    id: author._id.toString(),
    name: author.name,
  }));
}
NewPostPage function · typescript · L16-L31 (16 LOC)
src/app/admin/posts/new/page.tsx
export default async function NewPostPage() {
  const session = await getServerSession(authOptions);
  const isAuthor = session?.user?.role === 'author';
  const authorId = isAuthor ? session?.user?.authorId : undefined;

  const authors = await getAuthors();

  return (
    <div>
      <h1 className="mb-8 text-2xl font-bold text-gray-900 dark:text-white">
        Create New Post
      </h1>
      <PostForm authors={authors} fixedAuthorId={authorId} />
    </div>
  );
}
getPosts function · typescript · L12-L41 (30 LOC)
src/app/admin/posts/page.tsx
async function getPosts(authorId?: string, tenantId?: string, page: number = 1) {
  await connectDB();

  // Build filter with tenant isolation
  const filter: Record<string, unknown> = {};

  // CRITICAL: Always filter by tenantId for data isolation
  if (tenantId) {
    filter.tenantId = tenantId;
  }

  if (authorId) {
    filter.author = authorId;
  }

  const skip = (page - 1) * POSTS_PER_PAGE;

  // Get posts with pagination and total count in parallel
  const [posts, total] = await Promise.all([
    Post.find(filter)
      .sort({ createdAt: -1 })
      .skip(skip)
      .limit(POSTS_PER_PAGE)
      .populate('author', 'name')
      .lean(),
    Post.countDocuments(filter),
  ]);

  return { posts, total, page, totalPages: Math.ceil(total / POSTS_PER_PAGE) };
}
Source: Repobility analyzer · https://repobility.com
AdminPostsPage function · typescript · L43-L207 (165 LOC)
src/app/admin/posts/page.tsx
export default async function AdminPostsPage({
  searchParams,
}: {
  searchParams: Promise<{ page?: string }>;
}) {
  const params = await searchParams;
  const currentPage = Math.max(1, parseInt(params.page || '1', 10));

  const session = await getServerSession(authOptions);
  const isAuthor = session?.user?.role === 'author';
  const authorId = isAuthor ? session?.user?.authorId : undefined;
  const tenantId = session?.user?.tenantId;

  const { posts, total, totalPages } = await getPosts(authorId, tenantId, currentPage);

  return (
    <div>
      <div className="mb-8 flex items-center justify-between">
        <h1 className="text-2xl font-bold text-gray-900 dark:text-white">
          {isAuthor ? 'My Posts' : 'Posts'}
        </h1>
        <Link
          href="/admin/posts/new"
          className="flex items-center gap-2 rounded-lg bg-primary-600 px-4 py-2 text-sm font-medium text-white hover:bg-primary-700"
        >
          <Plus className="h-4 w-4" />
          New Post
 
UsersPage function · typescript · L28-L319 (292 LOC)
src/app/admin/users/page.tsx
export default function UsersPage() {
  const [users, setUsers] = useState<UserData[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [searchQuery, setSearchQuery] = useState('');
  const [roleFilter, setRoleFilter] = useState<string>('all');
  const [updating, setUpdating] = useState<string | null>(null);

  useEffect(() => {
    fetchUsers();
  }, []);

  const fetchUsers = async () => {
    try {
      const response = await fetch('/api/admin/users');
      const data = await response.json();

      if (data.success) {
        setUsers(data.data);
      } else {
        setError(data.error || 'Failed to fetch users');
      }
    } catch (err) {
      setError('Failed to fetch users');
    } finally {
      setLoading(false);
    }
  };

  const handleRoleChange = async (userId: string, newRole: string) => {
    setUpdating(userId);
    try {
      const response = await fetch('/api/admin/users', {
        method: 'PATCH',
    
GET function · typescript · L11-L162 (152 LOC)
src/app/api/admin/analytics/route.ts
export async function GET() {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;

    await connectDB();

    // Get tenant context
    const { tenantId } = await getTenantFromHeaders();
    const userTenantId = user.tenantId || tenantId;

    if (!userTenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    // Check if analytics is allowed for this tenant
    const tenant = await Tenant.findById(userTenantId).select('plan limits').lean();

    if (!tenant) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    // Analytics available for all paid plans (Basic, Pro, Enterprise)
    const analyticsAllowed = tenant.limits?.analyticsAllowed ||
      tenant.plan === 'basic' ||
      tenant.plan === 'pro' ||
      tenant.plan === 'ente
GET function · typescript · L11-L31 (21 LOC)
src/app/api/admin/authors/[id]/route.ts
export async function GET(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized - Admin access required' }, { status: 401 });
    }

    const { id } = await params;
    await connectDB();
    const author = await Author.findById(id);

    if (!author) {
      return NextResponse.json({ error: 'Author not found' }, { status: 404 });
    }

    return NextResponse.json({ success: true, data: author });
  } catch (error: any) {
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
PUT function · typescript · L33-L73 (41 LOC)
src/app/api/admin/authors/[id]/route.ts
export async function PUT(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized - Admin access required' }, { status: 401 });
    }

    const { id } = await params;
    const body = await request.json();
    const { name, email, password, avatar, bio, role, canLogin, canPost, social } = body;

    await connectDB();

    const author = await Author.findById(id);
    if (!author) {
      return NextResponse.json({ error: 'Author not found' }, { status: 404 });
    }

    // Update fields explicitly
    if (name !== undefined) author.name = name;
    if (email !== undefined) author.email = email;
    if (avatar !== undefined) author.avatar = avatar;
    if (bio !== undefined) author.bio = bio;
    if (role !== undefined) author.role = role;
    if (canLogin !== undefined) author.canLogin = canLogin;
    if (canPost !== undefined) a
DELETE function · typescript · L75-L95 (21 LOC)
src/app/api/admin/authors/[id]/route.ts
export async function DELETE(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized - Admin access required' }, { status: 401 });
    }

    const { id } = await params;
    await connectDB();

    const author = await Author.findByIdAndDelete(id);
    if (!author) {
      return NextResponse.json({ error: 'Author not found' }, { status: 404 });
    }

    return NextResponse.json({ success: true, message: 'Author deleted' });
  } catch (error: any) {
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
GET function · typescript · L10-L65 (56 LOC)
src/app/api/admin/authors/route.ts
export async function GET(request: NextRequest) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized - Admin access required' }, { status: 401 });
    }

    const { user } = sessionResult;

    // Parse pagination parameters
    const searchParams = request.nextUrl.searchParams;
    const { page, limit } = validatePagination(
      searchParams.get('page') || undefined,
      searchParams.get('limit') || ADMIN_PAGE_SIZE,
      MAX_PAGE_SIZE
    );
    const skip = (page - 1) * limit;

    await connectDB();

    // Get tenant context
    const { tenantId } = await getTenantFromHeaders();
    const userTenantId = user.tenantId || tenantId;

    // Build filter with tenant isolation
    const filter: any = {};
    if (userTenantId) {
      filter.tenantId = userTenantId;
    }

    // Execute count and find in parallel for efficiency
    const [total, authors] = await Promise.
POST function · typescript · L67-L134 (68 LOC)
src/app/api/admin/authors/route.ts
export async function POST(request: NextRequest) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized - Admin access required' }, { status: 401 });
    }

    const { user } = sessionResult;

    await connectDB();

    // Get tenant context
    const { tenantId } = await getTenantFromHeaders();
    const userTenantId = user.tenantId || tenantId;

    // Check tenant limits if tenantId exists
    if (userTenantId) {
      const limitCheck = await checkTenantLimits(userTenantId, 'authors');
      if (!limitCheck.allowed) {
        return NextResponse.json({ error: limitCheck.message }, { status: 403 });
      }
    }

    const body = await request.json();
    const { name, email, password, avatar, bio, role, canLogin, canPost, social } = body;

    if (!name || !email) {
      return NextResponse.json({ error: 'Name and email are required' }, { status: 400 });
    }

    cons
Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
GET function · typescript · L6-L54 (49 LOC)
src/app/api/admin/available-plans/route.ts
export async function GET() {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    await connectDB();

    // Get all active plans sorted by sortOrder
    const plans = await Plan.find({ isActive: true })
      .sort({ sortOrder: 1 })
      .select('name slug description price limits features sortOrder')
      .lean();

    // Format plans for the billing page
    const formattedPlans = plans.map((plan) => ({
      _id: plan._id,
      name: plan.name,
      slug: plan.slug,
      description: plan.description,
      price: {
        monthly: plan.price.monthly,
        yearly: plan.price.yearly,
      },
      limits: {
        maxPosts: plan.limits.maxPosts,
        maxAuthors: plan.limits.maxAuthors,
        maxStorage: plan.limits.maxStorage,
        maxUsers: plan.limits.maxUsers,
        customDomainAllowed: plan.limits.customDomainAllowed
GET function · typescript · L14-L46 (33 LOC)
src/app/api/admin/categories/[id]/route.ts
export async function GET(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { id } = await params;
    await connectDB();

    const category = await Category.findById(id).lean();

    if (!category) {
      return NextResponse.json({ error: 'Category not found' }, { status: 404 });
    }

    const postCount = await Post.countDocuments({ category: (category as any).slug, published: true });

    return NextResponse.json({
      _id: (category as any)._id.toString(),
      name: (category as any).name,
      slug: (category as any).slug,
      description: (category as any).description,
      color: (category as any).color,
      isSystem: (category as any).isSystem || false,
      postCount,
    });
  } catch (error: any) {
    console.error('Error fetching category:', error);
    return
PUT function · typescript · L49-L123 (75 LOC)
src/app/api/admin/categories/[id]/route.ts
export async function PUT(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { id } = await params;
    await connectDB();

    const body = await request.json();
    const { name, description, color } = body;

    if (!name || !name.trim()) {
      return NextResponse.json({ error: 'Category name is required' }, { status: 400 });
    }

    const category = await Category.findById(id);

    if (!category) {
      return NextResponse.json({ error: 'Category not found' }, { status: 404 });
    }

    // Prevent renaming system categories (but allow color/description changes)
    if (category.isSystem && name.trim().toLowerCase() !== category.name.toLowerCase()) {
      return NextResponse.json(
        { error: 'Cannot rename system category. You can only change its color and description.' 
DELETE function · typescript · L126-L168 (43 LOC)
src/app/api/admin/categories/[id]/route.ts
export async function DELETE(request: NextRequest, { params }: RouteParams) {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { id } = await params;
    await connectDB();

    const category = await Category.findById(id);

    if (!category) {
      return NextResponse.json({ error: 'Category not found' }, { status: 404 });
    }

    // Prevent deleting system categories (like "Review")
    if (category.isSystem) {
      return NextResponse.json(
        { error: 'Cannot delete system category. This category is required for the platform to function.' },
        { status: 400 }
      );
    }

    // Check if category has posts
    const postCount = await Post.countDocuments({ category: category.slug });

    if (postCount > 0) {
      return NextResponse.json(
        { error: `Cannot delete category with ${postCount} posts. Move or
GET function · typescript · L10-L105 (96 LOC)
src/app/api/admin/categories/route.ts
export async function GET() {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;

    await connectDB();

    // Get tenant context
    const { tenantId } = await getTenantFromHeaders();
    const userTenantId = user.tenantId || tenantId;

    // Build filter with tenant isolation
    const filter: any = {};
    if (userTenantId) {
      filter.tenantId = userTenantId;
    }

    // Get categories from DB
    const dbCategories = await Category.find(filter).sort({ name: 1 }).lean();
    const dbSlugs = new Set(dbCategories.map((c: any) => c.slug));

    // Get all unique categories from posts (including unpublished) for this tenant
    const postCategories = await Post.distinct('category', filter);

    // Find orphaned categories (exist in posts but not in Category collection)
    const orphanedCategories = pos
POST function · typescript · L108-L163 (56 LOC)
src/app/api/admin/categories/route.ts
export async function POST(request: NextRequest) {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;

    await connectDB();

    // Get tenant context
    const { tenantId } = await getTenantFromHeaders();
    const userTenantId = user.tenantId || tenantId;

    const body = await request.json();
    const { name, description, color } = body;

    if (!name || !name.trim()) {
      return NextResponse.json({ error: 'Category name is required' }, { status: 400 });
    }

    // Check if category already exists for this tenant
    const existingQuery: any = {
      name: { $regex: new RegExp(`^${escapeRegex(name.trim())}$`, 'i') }
    };
    if (userTenantId) {
      existingQuery.tenantId = userTenantId;
    }

    const existing = await Category.findOne(existingQuery);

    if (existing) {
      return NextRes
POST function · typescript · L6-L83 (78 LOC)
src/app/api/admin/coupon/validate/route.ts
export async function POST(request: NextRequest) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    const body = await request.json();
    const { code, planSlug, originalPrice } = body;

    if (!code || !planSlug || originalPrice === undefined) {
      return NextResponse.json(
        { error: 'Missing required fields: code, planSlug, originalPrice' },
        { status: 400 }
      );
    }

    // Validate plan slug
    if (!['basic', 'pro', 'enterprise'].includes(planSlug)) {
      return NextResponse.json(
        { error: 'Invalid plan' },
        { status: 400 }
      );
    }

    const result = await validateCoupon({
      code,
 
GET function · typescript · L15-L72 (58 LOC)
src/app/api/admin/custom-domain/route.ts
export async function GET() {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    const tenant = await Tenant.findById(tenantId)
      .select('customDomain customDomainStatus customDomainVerifiedAt limits.customDomainAllowed plan slug')
      .lean();

    if (!tenant) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    return NextResponse.json({
      success: true,
      data: {
        customDomain: tenant.customDomain || null,
        status: tenant.customDomainStatus || 'none',
        verifiedAt: tenant.customDomainVerifiedAt || null,
        allowed: tenant.limits?.customDomainAllowed || false,
Repobility · severity-and-effort ranking · https://repobility.com
POST function · typescript · L75-L181 (107 LOC)
src/app/api/admin/custom-domain/route.ts
export async function POST(request: NextRequest) {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    const tenant = await Tenant.findById(tenantId);

    if (!tenant) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    // Check if custom domain is allowed for this plan
    if (!tenant.limits?.customDomainAllowed) {
      return NextResponse.json(
        { error: 'Custom domains are only available on Pro and Enterprise plans. Please upgrade.' },
        { status: 403 }
      );
    }

    const body = await request.json();
    const { domain } = body;

    if (!domain) {
      return NextResponse.json
PATCH function · typescript · L184-L278 (95 LOC)
src/app/api/admin/custom-domain/route.ts
export async function PATCH() {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    const tenant = await Tenant.findById(tenantId);

    if (!tenant) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    if (!tenant.customDomain) {
      return NextResponse.json(
        { error: 'No custom domain configured' },
        { status: 400 }
      );
    }

    const domain = tenant.customDomain;
    let verified = false;
    let verificationMethod = '';

    // Try CNAME verification
    try {
      const cnameRecords = await resolveCname(domain);
      if (cnameRecords.some((record: string) =>
        record.
DELETE function · typescript · L281-L317 (37 LOC)
src/app/api/admin/custom-domain/route.ts
export async function DELETE() {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    await Tenant.findByIdAndUpdate(tenantId, {
      $unset: {
        customDomain: 1,
        customDomainStatus: 1,
        customDomainVerifiedAt: 1
      },
    });

    return NextResponse.json({
      success: true,
      message: 'Custom domain removed successfully',
    });
  } catch (error) {
    console.error('Error removing custom domain:', error);
    return NextResponse.json(
      { error: 'Failed to remove custom domain' },
      { status: 500 }
    );
  }
}
getDnsHost function · typescript · L320-L326 (7 LOC)
src/app/api/admin/custom-domain/route.ts
function getDnsHost(domain: string): string {
  const parts = domain.split('.');
  if (parts.length > 2) {
    return parts[0]; // Return subdomain (e.g., 'blog' from 'blog.example.com')
  }
  return '@'; // Root domain
}
GET function · typescript · L8-L83 (76 LOC)
src/app/api/admin/dashboard/route.ts
export async function GET(request: NextRequest) {
  try {
    const sessionResult = await getAdminSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const isAuthor = user.role === 'author';

    await connectDB();

    // Get tenant ID from session
    const tenantId = user.tenantId;

    // Build filter
    const filter: any = {};
    if (tenantId) {
      filter.tenantId = tenantId;
    }

    // Authors only see their own posts in dashboard stats
    const postFilter: any = { ...filter };
    if (isAuthor && user.authorId) {
      postFilter.author = user.authorId;
    }

    // Get stats
    const [
      totalPosts,
      publishedPosts,
      totalCategories,
      totalAuthors,
      viewsAggregate,
      recentPosts,
    ] = await Promise.all([
      Post.countDocuments(postFilter),
      Post.countDocuments({ ...postFilter, published: true }),
  
GET function · typescript · L8-L33 (26 LOC)
src/app/api/admin/pages/[id]/route.ts
export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const tenantId = (session.user as any).tenantId;
    const { id } = await params;

    await connectDB();
    const page = await Page.findOne({ _id: id, tenantId }).lean();

    if (!page) {
      return NextResponse.json({ error: 'Page not found' }, { status: 404 });
    }

    return NextResponse.json({ success: true, data: page });
  } catch (error: any) {
    console.error('Error fetching page:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
PUT function · typescript · L36-L85 (50 LOC)
src/app/api/admin/pages/[id]/route.ts
export async function PUT(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const userRole = (session.user as any).role;
    if (userRole === 'author') {
      return NextResponse.json({ error: 'Authors cannot edit pages' }, { status: 403 });
    }

    const tenantId = (session.user as any).tenantId;
    const { id } = await params;
    const body = await request.json();

    await connectDB();

    // Check if slug is being changed and if new slug already exists
    if (body.slug) {
      const existingPage = await Page.findOne({
        tenantId,
        slug: body.slug.toLowerCase(),
        _id: { $ne: id },
      });
      if (existingPage) {
        return NextResponse.json({ error: 'A page with this slug already exists' }, { status: 400 });
      }
      body.slug = body.slu
DELETE function · typescript · L88-L118 (31 LOC)
src/app/api/admin/pages/[id]/route.ts
export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const userRole = (session.user as any).role;
    if (userRole === 'author') {
      return NextResponse.json({ error: 'Authors cannot delete pages' }, { status: 403 });
    }

    const tenantId = (session.user as any).tenantId;
    const { id } = await params;

    await connectDB();
    const page = await Page.findOneAndDelete({ _id: id, tenantId });

    if (!page) {
      return NextResponse.json({ error: 'Page not found' }, { status: 404 });
    }

    return NextResponse.json({ success: true, message: 'Page deleted' });
  } catch (error: any) {
    console.error('Error deleting page:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
Open data scored by Repobility · https://repobility.com
GET function · typescript · L8-L30 (23 LOC)
src/app/api/admin/pages/route.ts
export async function GET(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const tenantId = (session.user as any).tenantId;
    if (!tenantId) {
      return NextResponse.json({ error: 'No tenant associated' }, { status: 400 });
    }

    await connectDB();
    const pages = await Page.find({ tenantId })
      .sort({ createdAt: -1 })
      .lean();

    return NextResponse.json({ success: true, data: pages });
  } catch (error: any) {
    console.error('Error fetching pages:', error);
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}
POST function · typescript · L33-L84 (52 LOC)
src/app/api/admin/pages/route.ts
export async function POST(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const userRole = (session.user as any).role;
    if (userRole === 'author') {
      return NextResponse.json({ error: 'Authors cannot create pages' }, { status: 403 });
    }

    const tenantId = (session.user as any).tenantId;
    if (!tenantId) {
      return NextResponse.json({ error: 'No tenant associated' }, { status: 400 });
    }

    const body = await request.json();
    const { title, slug, template, content, sections, heroImage, heroTitle, heroSubtitle, showInNavbar, showInFooter, published } = body;

    if (!title || !slug) {
      return NextResponse.json({ error: 'Title and slug are required' }, { status: 400 });
    }

    // Check if slug already exists
    await connectDB();
    const existingPage = await Page.findOne({ tenantId, slug: slug.t
GET function · typescript · L11-L86 (76 LOC)
src/app/api/admin/plan-request/route.ts
export async function GET() {
  try {
    const sessionResult = await getOwnerSession();

    if (!sessionResult || !sessionResult.user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const { user } = sessionResult;
    const tenantId = user.tenantId;

    if (!tenantId) {
      return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
    }

    await connectDB();

    // Get the current pending request for this tenant (if any)
    const pendingRequest = await PlanRequest.findOne({
      tenantId,
      status: 'pending',
    })
      .sort({ createdAt: -1 })
      .lean();

    // Get platform settings for contact info
    let platformSettings = await PlatformSettings.findOne().lean() as IPlatformSettings | null;
    if (!platformSettings) {
      platformSettings = {
        contactEmail: '[email protected]',
      } as IPlatformSettings;
    }

    // Get tenant's current plan info including billing
    const tenant = aw
page 1 / 7next ›