From 683107bb9134217e708d3cd96d37f8cd99852d68 Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Sun, 26 Mar 2017 21:04:09 -0500 Subject: [PATCH 01/26] Fix trailing sentences, grammar, untypable characters, and remove poor quality articles. --- src/NadekoBot/data/typing_articles.json | 164 +++++------------------- 1 file changed, 34 insertions(+), 130 deletions(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index ab34341c..9850103f 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -9,7 +9,7 @@ }, { "Title":"Forensic and Legal Psychology", - "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime," + "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things." }, { "Title":"International Handbook of Psychology in Education", @@ -17,7 +17,7 @@ }, { "Title":"Handbook of Personality Psychology", - "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality" + "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality." }, { "Title":"Dictionary of Theories, Laws, and Concepts in Psychology", @@ -25,19 +25,7 @@ }, { "Title":"Essays on Plato's Psychology", - "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greek" - }, - { - "Title":"Psychology Statistics For Dummies", - "Text":"As an alternative to typical, lead-heavy statistics texts or supplements to assigned course reading, this is one book psychology students won't want to be without." - }, - { - "Title":"Doing Psychology Experiments", - "Text":"David W. Martin’s unique blend of informality, humor, clear instruction, and solid scholarship make this concise text a popular choice for research methods courses in psychology." - }, - { - "Title":"A Handbook of Research Methods for Clinical and Health", - "Text":"For both undergraduate and postgraduate students, the book will be essential in making them aware of the full range of techniques available to them, helping them to design scientifically rigorous experiments." + "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece." }, { "Title":"A History of Psychology", @@ -57,19 +45,19 @@ }, { "Title":"Psychology and Deterrence", - "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior in the international" + "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally." }, { "Title":"Psychology: An International Perspective", - "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia," + "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others." }, { "Title":"Psychology, Briefer Course", - "Text":"Despite its title, 'Psychology: Briefer Course' is more than a simple condensation of the great 'Principles of Psychology." + "Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology." }, { "Title":"Psychology, Seventh Edition (High School)", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field—cognition, gender and diversity studies, neuroscience and more, while at the same time using the most" + "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more." }, { "Title":"Psychology of Russia: Past, Present, Future", @@ -79,25 +67,17 @@ "Title":"Barron's AP Psychology", "Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review." }, - { - "Title":"Psychology for Inclusive Education: New Directions in", - "Text":"International in focus and at the very cutting edge of the field, this is essential reading for all those interested in the development of inclusive education." - }, { "Title":"Applied Psychology: Putting Theory Into Practice", "Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world." }, - { - "Title":"The Psychology of Science: A Reconnaissance", - "Text":"' This eBook edition contains the complete 168 page text of the original 1966 hardcover edition. Contents: Preface by Abraham H. Maslow Acknowledgments 1. Mechanistic and Humanistic Science 2." - }, { "Title":"Filipino American Psychology: A Handbook of Theory,", "Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard." }, { "Title":"The Psychology of Visual Illusion", - "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent 'movement' of images. 240 drawings. 1972 edition." + "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition." }, { "Title":"The Psychology of Women", @@ -105,15 +85,11 @@ }, { "Title":"Psychology and Race", - "Text":"' Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself." - }, - { - "Title":"Psychology for A-Level", - "Text":"'Precisely targeted at AQA A Level Psychology, specification A. It will also be of interest to those who are new to psychology, and who want to get a flavour of the kinds of topics in which psychologists are interested'--Preface, p. vii." + "Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery." }, { "Title":"Biological Psychology", - "Text":"Updated with new topics, examples, and recent research findings--and supported by new online bio-labs, part of the strongest media package yet--this text speaks to today’s students and instructors." + "Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors." }, { "Title":"Psychology: Concepts & Connections", @@ -121,15 +97,15 @@ }, { "Title":"The Psychology of Adoption", - "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have" + "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible." }, { "Title":"Psychology and Adult Learning", - "Text":"This new edition is thoroughly revised and updated in light of the impact of globalising processes and the application of new information technologies, and the influence of postmodernism on psychology." + "Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology." }, { "Title":"Gestalt Psychology: An Introduction to New Concepts in", - "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who" + "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts." }, { "Title":"The Psychology of Goals", @@ -139,29 +115,17 @@ "Title":"Metaphors in the History of Psychology", "Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology." }, - { - "Title":"Abnormal Psychology: An Integrative Approach", - "Text":"ABNORMAL PSYCHOLOGY: AN INTEGRATIVE APPROACH, Seventh Edition, is the perfect book to help you succeed in your abnormal psychology course!" - }, - { - "Title":"Art and Visual Perception: A Psychology of the Creative Eye", - "Text":"Gestalt theory and the psychology of visual perception form the basis for an analysis of art and its basic elements" - }, { "Title":"Psychology & Christianity: Five Views", "Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity." }, { "Title":"The Psychology of Hope: You Can Get There from Here", - "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In The Psychology of Hope, a professor of psychology reveals the specific character traits that produce highly hopeful individuals." + "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals." }, { "Title":"Perspectives on Psychology", - "Text":"This is a title in the modular 'Principles in Psychology Series', designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." - }, - { - "Title":"Psychology the Easy Way", - "Text":"Material is presented in a way that makes these books ideal as self-teaching guides, but Easy Way titles are also preferred by many teachers as supplements to classroom textbooks." + "Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." }, { "Title":"Ethics in Psychology: Professional Standards and Cases", @@ -169,35 +133,23 @@ }, { "Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,", - "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas'--Provided by publisher." - }, - { - "Title":"Psychology for Physical Educators: Student in Focus", - "Text":"This updated edition focuses on attitude and motivation as important aspects of the physical education curriculum, illustrating practical ideas and pedagogical solutions for any PE setting." + "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas." }, { "Title":"The Psychology of Leadership: New Perspectives and Research", - "Text":"In this book, some of the world's leading scholars come together to describe their thinking and research on the topic of the psychology of leadership." + "Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership." }, { "Title":"The Psychology of Interpersonal Relations", - "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term 'interpersonal relations' denotes relations between a few, usually between two, people." - }, - { - "Title":"Applied Psychology", - "Text":"The chapters on Counselling Psychology and Teaching Psychology are available online via the Student Companion Site at: http://tinyurl.com/c3ztvtj The text is written to be accessible to Level 1 Introductory Psychology students, and also to" + "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people." }, { "Title":"Psychology", "Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field." }, - { - "Title":"The Psychology of Music", - "Text":"On interpreting musical phenomena in terms of mental function" - }, { "Title":"Abnormal Psychology", - "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of" + "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs." }, { "Title":"The Psychology of Food Choice", @@ -205,19 +157,15 @@ }, { "Title":"Psychology: brain, behavior, & culture", - "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know or new ways of thinking about things they did know." + "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know." }, { "Title":"A Brief History of Psychology", - "Text":"Due to its brevity and engaging style, the book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." - }, - { - "Title":"Psychology AS: The Complete Companion", - "Text":"Presented in double-page spreads this book written to the average AS ability level, provides information on psychology in bite-sized chunks with learning and revision features." + "Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." }, { "Title":"The Psychology Book: From Shamanism to Cutting-Edge", - "Text":"Lavishly illustrated, this new addition in the Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." + "Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." }, { "Title":"The Psychology Book", @@ -225,15 +173,15 @@ }, { "Title":"Handbook of Positive Psychology", - "Text":"' The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." + "Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." }, { "Title":"Psychology of Sustainable Development", - "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned" + "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment." }, { "Title":"An Introduction to the History of Psychology", - "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for hundreds-or even thousands-of years." + "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years." }, { "Title":"Careers in Psychology: Opportunities in a Changing World", @@ -241,39 +189,23 @@ }, { "Title":"Philosophy of Psychology", - "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of" + "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class." }, { "Title":"The Psychology of Risk Taking Behavior", "Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship." }, { - "Title":"The Nazi Doctors: Medical Killing and the Psychology of", - "Text":"This book explores the psychological conditions that promote the human potential for evil, relating medical killing to broader principles of doubling and genocide" - }, - { - "Title":"The Body and Psychology", - "Text":"The material in this volume was previously published as a Special Issue of th" - }, - { - "Title":"Introduction to Psychology: Gateways to Mind and Behavior", + "Title":"Legal Notices", "Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version." }, - { - "Title":"Psychology of Time", - "Text":"Basic Structure The book would contain 14 or 15 chapters of roughly 12 000 words. The exact final number of chapters would depend on further discussions with you about the book's basic structure." - }, { "Title":"Handbook of Psychology, Experimental Psychology", "Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area." }, - { - "Title":"Study Guide for Psychology, Seventh Edition", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field--cognition, gender and diversity studies, neuroscience and more, while at the same time using the most" - }, { "Title":"Culture and Psychology", - "Text":"In addition, the text encourages students to question traditionally held beliefs and theories as and their relevance to different cultural groups today." + "Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today." }, { "Title":"Exploring the Psychology of Interest", @@ -289,43 +221,23 @@ }, { "Title":"The Psychology of Social Class", - "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation and other personality variables on social mobility and the effect" - }, - { - "Title":"Applied Psychology: Current Issues and New Directions", - "Text":"Key features of this book: - Consistently pedagogical throughout - chapter summaries, questions for reflection and discussion and annotated further reading in every chapter - Comprehensive coverage - all areas of applied psychology included" + "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery." }, { "Title":"Popular Psychology: An Encyclopedia", "Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder." }, - { - "Title":"Advanced Psychology: Applications, Issues and Perspectives", - "Text":"The second of two books, Advanced Psychology covers units 4 to 6 for the second year at Advanced Level." - }, - { - "Title":"Mindset: The New Psychology of Success", - "Text":"This is a book that can change your life, as its ideas have changed mine.”—Robert J. Sternberg, IBM Professor of Education and Psychology at Yale University, director of the PACE Center of Yale University, and author of Successful" - }, { "Title":"E-Z Psychology", - "Text":"This book covers material as it is taught on a college-101 level." - }, - { - "Title":"Myers' Psychology for AP*", - "Text":"Already The Bestselling AP* Psychology Author, Myers Writes His First Exclusive AP* Psych Text Watch Dave G. Myers introduce this new text here." + "Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know." }, { "Title":"Psychology and Health", "Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know." }, - { - "Title":"Applying Psychology in Business: The Handbook for Managers", - "Text":"To learn more about Rowman & Littlefield titles please visit us at www.rowmanlittlefield.com." - }, { "Title":"Influence", - "Text":"Influence, the classic book on persuasion, explains the psychology of why people say 'yes'—and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." + "Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." }, { "Title":"Psychology and Policing", @@ -333,11 +245,7 @@ }, { "Title":"Applied Psychology: New Frontiers and Rewarding Careers", - "Text":"This book examines how psychological science is, and can be, used to prevent and ameliorate pressing human problems to promote positive social change." - }, - { - "Title":"Psychology: Concepts and Applications", - "Text":"Nevid developed the effective teaching devices in this text based on a comprehensive system derived from research on learning and memory as well as his own research on textbook pedagogy." + "Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change." }, { "Title":"Foundations of Sport and Exercise Psychology, 6E: ", @@ -345,7 +253,7 @@ }, { "Title":"Biographical Dictionary of Psychology", - "Text":"This Dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." + "Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." }, { "Title":"Psychology: A Self-Teaching Guide", @@ -354,8 +262,4 @@ { "Title":"A Dictionary of Psychology", "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." - }, - { - "Title":"An Intellectual History of Psychology", - "Text":"Invaluable as a text for students and as a stimulating and insightful overview for scholars and practicing psychologists, this volume can be read either as a history of psychology in both its philosophical and aspiring scientific periods or" - }] \ No newline at end of file + }] From 1bf1dc90779f92f38657360e57fcf9627567be01 Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Mon, 27 Mar 2017 08:26:11 -0500 Subject: [PATCH 02/26] Add more articles, mostly sourced from the ancient fortunes program for posix os's. Please review and reject any you find objectionable. I wasn't given any guidelines on how to pick these. I may add more after some feedback. --- src/NadekoBot/data/typing_articles.json | 272 ++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 9850103f..4666a5e7 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -262,4 +262,276 @@ { "Title":"A Dictionary of Psychology", "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." + }, + { + "Title":"darbian regarding how fast you can learn to speedrun" + "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." + }, + { + "Title":"Memes" + "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." + }, + { + "Title":"Literature quotes" + "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" + }, + { + "Title":"Literature quotes" + "Text":"All generalizations are false, including this one. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" + }, + { + "Title":"Literature quotes" + "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" + }, + { + "Title":"Literature quotes" + "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" + }, + { + "Title":"Pat Cadigan, \"Mindplayers\"" + "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." + }, + { + "Title":"Men & Women" + "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" + }, + { + "Title":"James L. Collymore, \"Perfect Woman\"" + "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." + }, + { + "Title":"Famous quotes" + "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" + }, + { + "Title":"Men & Women" + "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" + }, + { + "Title":"Encyclopadia Apocryphia, 1990 ed." + "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." + }, + { + "Title":"Susan Gordon" + "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." + }, + { + "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"" + "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." + }, + { + "Title":"Medicine" + "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." + }, + { + "Title":"Medicine" + "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." + }, + { + "Title":"The C Programming Language" + "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." + }, + { + "Title":"Religious Texts" + "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" + }, + { + "Title":"Religious Texts" + "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" + }, + { + "Title":"Religious Texts" + "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" + }, + { + "Title":"Religious Texts" + "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" + }, + { + "Title":"Religious Texts" + "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" + }, + { + "Title":"Religious Texts" + "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" + }, + { + "Title":"Medicine" + "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" + }, + { + "Title":"Medicine" + "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" + }, + { + "Title":"Medicine" + "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" + }, + { + "Title":"Science" + "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" + }, + { + "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"" + "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." + }, + { + "Title":"#Octalthorpe" + "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." + }, + { + "Title":"Science -- Edgar R. Fiedler" + "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." + }, + { + "Title":"Science -- R. Buckminster Fuller" + "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." + }, + { + "Title":"Math" + "Text":"Factorials were someone's attempt to make math LOOK exciting." + }, + { + "Title":"Science -- Thomas L. Creed" + "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." + }, + { + "Title":"Science -- H. L. Mencken, 1930" + "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." + }, + { + "Title":"Science" + "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." + }, + { + "Title":"Science -- Stanislaw Lem" + "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." + }, + { + "Title":"Science -- Dave Barry" + "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." + }, + { + "Title":"Sports" + "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" + }, + { + "Title":"Sports" + "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" + }, + { + "Title":"Sports" + "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." + }, + { + "Title":"Sports" + "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" + }, + { + "Title":"Sports" + "Text":"The surest way to remain a winner is to win once, and then not play any more." + }, + { + "Title":"Sports" + "Text":"The real problem with hunting elephants is carrying the decoys" + }, + { + "Title":"Sports -- Dizzy Dean" + "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." + }, + { + "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium" + "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." + }, + { + "Title":"Sports" + "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." + }, + { + "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"" + "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." + }, + { + "Title":"Smart House" + "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" + }, + { + "Title":"Linux -- Jim Wright" + "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." + }, + { + "Title":"True Words of a Genius Philosopher" + "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." + }, + { + "Title":"Politics -- Donald Trump" + "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." + }, + { + "Title":"Politics -- Sir Winston Churchill, 1952" + "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." + }, + { + "Title":"Politics -- Johnny Hart" + "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." + }, + { + "Title":"Politics -- Winston Churchill" + "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." + }, + { + "Title":"Politics" + "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." + }, + { + "Title":"Politics -- A Yippie Proverb" + "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." + }, + { + "Title":"Politics -- Boss Tweed" + "Text":"I don't care who does the electing as long as I get to do the nominating." + }, + { + "Title":"Politics -- Francis Bellamy, 1892" + "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." + }, + { + "Title":"Politics -- Napoleon" + "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." + }, + { + "Title":"Politics" + "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." + }, + { + "Title":"Politics -- Frederick Douglass" + "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." }] From 13d6775b2f1d2f265ba45dde752b1cb29a660eef Mon Sep 17 00:00:00 2001 From: Hubcapp Date: Mon, 27 Mar 2017 08:45:58 -0500 Subject: [PATCH 03/26] I think you'll need these. --- src/NadekoBot/data/typing_articles.json | 136 ++++++++++++------------ 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json index 4666a5e7..054573a0 100644 --- a/src/NadekoBot/data/typing_articles.json +++ b/src/NadekoBot/data/typing_articles.json @@ -264,274 +264,274 @@ "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." }, { - "Title":"darbian regarding how fast you can learn to speedrun" + "Title":"darbian regarding how fast you can learn to speedrun", "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." }, { - "Title":"Memes" + "Title":"Memes", "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All generalizations are false, including this one. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" }, { - "Title":"Literature quotes" + "Title":"Literature quotes", "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" }, { - "Title":"Pat Cadigan, \"Mindplayers\"" + "Title":"Pat Cadigan, \"Mindplayers\"", "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." }, { - "Title":"Men & Women" + "Title":"Men & Women", "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" }, { - "Title":"James L. Collymore, \"Perfect Woman\"" + "Title":"James L. Collymore, \"Perfect Woman\"", "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." }, { - "Title":"Famous quotes" + "Title":"Famous quotes", "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" }, { - "Title":"Men & Women" + "Title":"Men & Women", "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" }, { - "Title":"Encyclopadia Apocryphia, 1990 ed." + "Title":"Encyclopadia Apocryphia, 1990 ed.", "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." }, { - "Title":"Susan Gordon" + "Title":"Susan Gordon", "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." }, { - "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"" + "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"", "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." }, { - "Title":"The C Programming Language" + "Title":"The C Programming Language", "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" }, { - "Title":"Religious Texts" + "Title":"Religious Texts", "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" }, { - "Title":"Medicine" + "Title":"Medicine", "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" }, { - "Title":"Science" + "Title":"Science", "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" }, { - "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"" + "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"", "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." }, { - "Title":"#Octalthorpe" + "Title":"#Octalthorpe", "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." }, { - "Title":"Science -- Edgar R. Fiedler" + "Title":"Science -- Edgar R. Fiedler", "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." }, { - "Title":"Science -- R. Buckminster Fuller" + "Title":"Science -- R. Buckminster Fuller", "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." }, { - "Title":"Math" + "Title":"Math", "Text":"Factorials were someone's attempt to make math LOOK exciting." }, { - "Title":"Science -- Thomas L. Creed" + "Title":"Science -- Thomas L. Creed", "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." }, { - "Title":"Science -- H. L. Mencken, 1930" + "Title":"Science -- H. L. Mencken, 1930", "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." }, { - "Title":"Science" + "Title":"Science", "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." }, { - "Title":"Science -- Stanislaw Lem" + "Title":"Science -- Stanislaw Lem", "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." }, { - "Title":"Science -- Dave Barry" + "Title":"Science -- Dave Barry", "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." }, { - "Title":"Sports" + "Title":"Sports", "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" }, { - "Title":"Sports" + "Title":"Sports", "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" }, { - "Title":"Sports" + "Title":"Sports", "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." }, { - "Title":"Sports" + "Title":"Sports", "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" }, { - "Title":"Sports" + "Title":"Sports", "Text":"The surest way to remain a winner is to win once, and then not play any more." }, { - "Title":"Sports" + "Title":"Sports", "Text":"The real problem with hunting elephants is carrying the decoys" }, { - "Title":"Sports -- Dizzy Dean" + "Title":"Sports -- Dizzy Dean", "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." }, { - "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium" + "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium", "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." }, { - "Title":"Sports" + "Title":"Sports", "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." }, { - "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"" + "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"", "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." }, { - "Title":"Smart House" + "Title":"Smart House", "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" }, { - "Title":"Linux -- Jim Wright" + "Title":"Linux -- Jim Wright", "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." }, { - "Title":"True Words of a Genius Philosopher" + "Title":"True Words of a Genius Philosopher", "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." }, { - "Title":"Politics -- Donald Trump" + "Title":"Politics -- Donald Trump", "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." }, { - "Title":"Politics -- Sir Winston Churchill, 1952" + "Title":"Politics -- Sir Winston Churchill, 1952", "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." }, { - "Title":"Politics -- Johnny Hart" + "Title":"Politics -- Johnny Hart", "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." }, { - "Title":"Politics -- Winston Churchill" + "Title":"Politics -- Winston Churchill", "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." }, { - "Title":"Politics" + "Title":"Politics", "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." }, { - "Title":"Politics -- A Yippie Proverb" + "Title":"Politics -- A Yippie Proverb", "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." }, { - "Title":"Politics -- Boss Tweed" + "Title":"Politics -- Boss Tweed", "Text":"I don't care who does the electing as long as I get to do the nominating." }, { - "Title":"Politics -- Francis Bellamy, 1892" + "Title":"Politics -- Francis Bellamy, 1892", "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." }, { - "Title":"Politics -- Napoleon" + "Title":"Politics -- Napoleon", "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." }, { - "Title":"Politics" + "Title":"Politics", "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." }, { - "Title":"Politics -- Frederick Douglass" + "Title":"Politics -- Frederick Douglass", "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." }] From ec24ac38864b78faa6340bde78f29524667c4cbf Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 08:34:35 +0200 Subject: [PATCH 04/26] Added a big part of basic patreon stuff, but can't activate it yet, waiting for their email reply to check some things --- .../Utility/Commands/PatreonCommands.cs | 182 ++++++++++-------- .../Modules/Utility/Models/PatreonData.cs | 31 ++- .../Modules/Utility/Models/PatreonPledge.cs | 68 +++++++ .../Modules/Utility/Models/PatreonUser.cs | 70 +++++++ .../Database/Models/PatreonRewards.cs | 15 ++ 5 files changed, 271 insertions(+), 95 deletions(-) create mode 100644 src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs create mode 100644 src/NadekoBot/Modules/Utility/Models/PatreonUser.cs create mode 100644 src/NadekoBot/Services/Database/Models/PatreonRewards.cs diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index b347330f..c8908abe 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -1,78 +1,110 @@ -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; -using Discord.Commands; -using Discord; -using NadekoBot.Attributes; -using NadekoBot.Modules.Utility.Models; -using Newtonsoft.Json; +//using System.Collections.Generic; +//using System.Linq; +//using System.Net.Http; +//using System.Threading.Tasks; +//using Discord.Commands; +//using NadekoBot.Attributes; +//using NadekoBot.Modules.Utility.Models; +//using Newtonsoft.Json; +//using System.Threading; +//using System; +//using System.Collections.Immutable; -namespace NadekoBot.Modules.Utility -{ - public partial class Utility - { - //[Group] - //public class PatreonCommands : NadekoSubmodule - //{ - // [NadekoCommand, Usage, Description, Aliases] - // [RequireContext(ContextType.Guild)] - // public async Task ClaimPatreonRewards([Remainder] string arg) - // { - // var pledges = await GetPledges2(); - // } +//namespace NadekoBot.Modules.Utility +//{ +// public partial class Utility +// { +// [Group] +// public class PatreonCommands : NadekoSubmodule +// { +// [NadekoCommand, Usage, Description, Aliases] +// public async Task ClaimPatreonRewards() +// { +// var patreon = PatreonThingy.Instance; - // private static async Task GetPledges() - // { - // var pledges = new List(); - // using (var http = new HttpClient()) - // { - // http.DefaultRequestHeaders.Clear(); - // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); - // var data = new PatreonData() - // { - // Links = new Links() - // { - // Next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" - // } - // }; - // do - // { - // var res = - // await http.GetStringAsync(data.Links.Next) - // .ConfigureAwait(false); - // data = JsonConvert.DeserializeObject(res); - // pledges.AddRange(data.Data); - // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); - // } - // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); - // } +// var pledges = (await patreon.GetPledges().ConfigureAwait(false)) +// .OrderByDescending(x => x.Reward.attributes.amount_cents); - // private static async Task GetPledges2() - // { - // var pledges = new List(); - // using (var http = new HttpClient()) - // { - // http.DefaultRequestHeaders.Clear(); - // http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); - // var data = new PatreonData() - // { - // Links = new Links() - // { - // Next = "https://api.patreon.com/oauth2/api/current_user/campaigns?include=pledges" - // } - // }; - // do - // { - // var res = - // await http.GetStringAsync(data.Links.Next) - // .ConfigureAwait(false); - // data = JsonConvert.DeserializeObject(res); - // pledges.AddRange(data.Data); - // } while (!string.IsNullOrWhiteSpace(data.Links.Next)); - // } - // return pledges.Where(x => string.IsNullOrWhiteSpace(x.Attributes.declined_since)).ToArray(); - // } - //} - } -} +// if (pledges == null) +// { +// await ReplyErrorLocalized("pledges_loading").ConfigureAwait(false); +// return; +// } + +// } +// } + +// public class PatreonThingy +// { +// public static PatreonThingy _instance = new PatreonThingy(); +// public static PatreonThingy Instance => _instance; + +// private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); + +// private ImmutableArray pledges; + +// static PatreonThingy() { } + +// public async Task> GetPledges() +// { +// try +// { +// await LoadPledges().ConfigureAwait(false); +// return pledges; +// } +// catch (OperationCanceledException) +// { +// return pledges; +// } +// } + +// public async Task LoadPledges() +// { +// await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); +// try +// { +// var rewards = new List(); +// var users = new List(); +// using (var http = new HttpClient()) +// { +// http.DefaultRequestHeaders.Clear(); +// http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); +// var data = new PatreonData() +// { +// Links = new PatreonDataLinks() +// { +// next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" +// } +// }; +// do +// { +// var res = await http.GetStringAsync(data.Links.next) +// .ConfigureAwait(false); +// data = JsonConvert.DeserializeObject(res); +// var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); +// rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) +// .Where(x => x.attributes.declined_since == null)); +// users.AddRange(data.Included +// .Where(x => x["type"].ToString() == "user") +// .Select(x => JsonConvert.DeserializeObject(x.ToString()))); +// } while (!string.IsNullOrWhiteSpace(data.Links.next)); +// } +// pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() +// { +// User = y, +// Reward = x, +// }).ToImmutableArray(); +// } +// finally +// { +// var _ = Task.Run(async () => +// { +// await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); +// getPledgesLocker.Release(); +// }); + +// } +// } +// } +// } +//} diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonData.cs b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs index 381666e8..87ab3f91 100644 --- a/src/NadekoBot/Modules/Utility/Models/PatreonData.cs +++ b/src/NadekoBot/Modules/Utility/Models/PatreonData.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json.Linq; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,32 +7,22 @@ using System.Threading.Tasks; namespace NadekoBot.Modules.Utility.Models { - public class PatreonData { - public Pledge[] Data { get; set; } - public Links Links { get; set; } + public JObject[] Included { get; set; } + public JObject[] Data { get; set; } + public PatreonDataLinks Links { get; set; } } - public class Attributes + public class PatreonDataLinks { - public int amount_cents { get; set; } - public string created_at { get; set; } - public string declined_since { get; set; } - public bool is_twitch_pledge { get; set; } - public bool patron_pays_fees { get; set; } - public int pledge_cap_cents { get; set; } + public string first { get; set; } + public string next { get; set; } } - public class Pledge + public class PatreonUserAndReward { - public Attributes Attributes { get; set; } - public int Id { get; set; } - } - - public class Links - { - public string First { get; set; } - public string Next { get; set; } + public PatreonUser User { get; set; } + public PatreonPledge Reward { get; set; } } } diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs b/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs new file mode 100644 index 00000000..1ea3bd3a --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Models/PatreonPledge.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility.Models +{ + public class Attributes + { + public int amount_cents { get; set; } + public string created_at { get; set; } + public object declined_since { get; set; } + public bool is_twitch_pledge { get; set; } + public bool patron_pays_fees { get; set; } + public int pledge_cap_cents { get; set; } + } + + public class Address + { + public object data { get; set; } + } + + public class Data + { + public string id { get; set; } + public string type { get; set; } + } + + public class Links + { + public string related { get; set; } + } + + public class Creator + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Patron + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Reward + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class Relationships + { + public Address address { get; set; } + public Creator creator { get; set; } + public Patron patron { get; set; } + public Reward reward { get; set; } + } + + public class PatreonPledge + { + public Attributes attributes { get; set; } + public string id { get; set; } + public Relationships relationships { get; set; } + public string type { get; set; } + } +} diff --git a/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs b/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs new file mode 100644 index 00000000..353a493a --- /dev/null +++ b/src/NadekoBot/Modules/Utility/Models/PatreonUser.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Utility.Models +{ + public class DiscordConnection + { + public string user_id { get; set; } + } + + public class SocialConnections + { + public object deviantart { get; set; } + public DiscordConnection discord { get; set; } + public object facebook { get; set; } + public object spotify { get; set; } + public object twitch { get; set; } + public object twitter { get; set; } + public object youtube { get; set; } + } + + public class UserAttributes + { + public string about { get; set; } + public string created { get; set; } + public object discord_id { get; set; } + public string email { get; set; } + public object facebook { get; set; } + public object facebook_id { get; set; } + public string first_name { get; set; } + public string full_name { get; set; } + public int gender { get; set; } + public bool has_password { get; set; } + public string image_url { get; set; } + public bool is_deleted { get; set; } + public bool is_nuked { get; set; } + public bool is_suspended { get; set; } + public string last_name { get; set; } + public SocialConnections social_connections { get; set; } + public int status { get; set; } + public string thumb_url { get; set; } + public object twitch { get; set; } + public string twitter { get; set; } + public string url { get; set; } + public string vanity { get; set; } + public object youtube { get; set; } + } + + public class Campaign + { + public Data data { get; set; } + public Links links { get; set; } + } + + public class UserRelationships + { + public Campaign campaign { get; set; } + } + + public class PatreonUser + { + public UserAttributes attributes { get; set; } + public string id { get; set; } + public UserRelationships relationships { get; set; } + public string type { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs new file mode 100644 index 00000000..0e1532b3 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Models +{ + public class PatreonRewards : DbEntity + { + public ulong UserId { get; set; } + public ulong PledgeCents { get; set; } + public ulong Awarded { get; set; } + } +} From 1704f93218ecf7e40a953b42abc63456b878d606 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 10:55:45 +0200 Subject: [PATCH 05/26] Typing articles updated --- .../Games/Commands/SpeedTypingCommands.cs | 2 +- src/NadekoBot/data/typing_articles.json | 537 ------------------ src/NadekoBot/data/typing_articles2.json | 1 + 3 files changed, 2 insertions(+), 538 deletions(-) delete mode 100644 src/NadekoBot/data/typing_articles.json create mode 100644 src/NadekoBot/data/typing_articles2.json diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 7dec0992..048aab0f 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Games { public static List TypingArticles { get; } = new List(); - private const string _typingArticlesPath = "data/typing_articles.json"; + private const string _typingArticlesPath = "data/typing_articles2.json"; static SpeedTypingCommands() { diff --git a/src/NadekoBot/data/typing_articles.json b/src/NadekoBot/data/typing_articles.json deleted file mode 100644 index 054573a0..00000000 --- a/src/NadekoBot/data/typing_articles.json +++ /dev/null @@ -1,537 +0,0 @@ -[ - { - "Title":"The Gender of Psychology", - "Text":"This book addresses the diversity of psychological knowledge and practice through the lens of gender." - }, - { - "Title":"Unto Others: The Evolution and Psychology of Unselfish", - "Text":"In Unto Others philosopher Elliott Sober and biologist David Sloan Wilson demonstrate once and for all that unselfish behavior is in fact an important feature of both biological and human nature." - }, - { - "Title":"Forensic and Legal Psychology", - "Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things." - }, - { - "Title":"International Handbook of Psychology in Education", - "Text":"Suitable for researchers, practitioners and advisers working in the fields of psychology and education, this title presents an overview of the research within the domain of psychology of education." - }, - { - "Title":"Handbook of Personality Psychology", - "Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality." - }, - { - "Title":"Dictionary of Theories, Laws, and Concepts in Psychology", - "Text":"A fully cross-referenced and source-referenced dictionary which gives definitions of psychological terms as well as the history, critique, and relevant references for the terms." - }, - { - "Title":"Essays on Plato's Psychology", - "Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece." - }, - { - "Title":"A History of Psychology", - "Text":"First published in 2002. Routledge is an imprint of Taylor & Francis, an informa company." - }, - { - "Title":"An Introduction to the Psychology of Religion", - "Text":"The third edition of this successful book, which applies the science of psychology to problems of religion. Dr Thouless explores such questions as: why do people believe? Why are their beliefs often held with irrational strength?" - }, - { - "Title":"Psychology of Champions: How to Win at Sports and Life", - "Text":"In this unprecedented book, two psychologist researchers interview sports legends and super-athletes across sports to explain the thinking that powers stellar performers, pushing them to amazing and historic successes." - }, - { - "Title":"The Psychology of Humor: An Integrative Approach", - "Text":"This is a singly authored monograph that provides in one source, a summary of information researchers might wish to know about research into the psychology of humor." - }, - { - "Title":"Psychology and Deterrence", - "Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally." - }, - { - "Title":"Psychology: An International Perspective", - "Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others." - }, - { - "Title":"Psychology, Briefer Course", - "Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology." - }, - { - "Title":"Psychology, Seventh Edition (High School)", - "Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more." - }, - { - "Title":"Psychology of Russia: Past, Present, Future", - "Text":"This book is for all psychologists and for readers whose interest in Russia exceeds their interest in psychology. Readers of this book will quickly discover a new world of thought." - }, - { - "Title":"Barron's AP Psychology", - "Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review." - }, - { - "Title":"Applied Psychology: Putting Theory Into Practice", - "Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world." - }, - { - "Title":"Filipino American Psychology: A Handbook of Theory,", - "Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard." - }, - { - "Title":"The Psychology of Visual Illusion", - "Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition." - }, - { - "Title":"The Psychology of Women", - "Text":"This highly respected text offers students an enjoyable, extraordinarily well-written introduction to the psychology of women with an up-to-date examination of the field and comprehensive coverage of topics." - }, - { - "Title":"Psychology and Race", - "Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery." - }, - { - "Title":"Biological Psychology", - "Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors." - }, - { - "Title":"Psychology: Concepts & Connections", - "Text":"The theme of this book is applying theories and research to learning and to contemporary life." - }, - { - "Title":"The Psychology of Adoption", - "Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible." - }, - { - "Title":"Psychology and Adult Learning", - "Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology." - }, - { - "Title":"Gestalt Psychology: An Introduction to New Concepts in", - "Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts." - }, - { - "Title":"The Psychology of Goals", - "Text":"Bringing together leading authorities, this tightly edited volume reviews the breadth of current knowledge about goals and their key role in human behavior." - }, - { - "Title":"Metaphors in the History of Psychology", - "Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology." - }, - { - "Title":"Psychology & Christianity: Five Views", - "Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity." - }, - { - "Title":"The Psychology of Hope: You Can Get There from Here", - "Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals." - }, - { - "Title":"Perspectives on Psychology", - "Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context." - }, - { - "Title":"Ethics in Psychology: Professional Standards and Cases", - "Text":"In this book, their main intent is to present the full range of contemporary ethical issues in psychology as not only relevant and intriguing, but also as integral and unavoidable aspects of the profession." - }, - { - "Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,", - "Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas." - }, - { - "Title":"The Psychology of Leadership: New Perspectives and Research", - "Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership." - }, - { - "Title":"The Psychology of Interpersonal Relations", - "Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people." - }, - { - "Title":"Psychology", - "Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field." - }, - { - "Title":"Abnormal Psychology", - "Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs." - }, - { - "Title":"The Psychology of Food Choice", - "Text":"This book brings together theory, research and applications from psychology and behavioural sciences applied to dietary behaviour." - }, - { - "Title":"Psychology: brain, behavior, & culture", - "Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know." - }, - { - "Title":"A Brief History of Psychology", - "Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field." - }, - { - "Title":"The Psychology Book: From Shamanism to Cutting-Edge", - "Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries." - }, - { - "Title":"The Psychology Book", - "Text":"All the big ideas, simply explained - an innovative and accessible guide to the study of human nature The Psychology Book clearly explains more than 100 groundbreaking ideas in this fascinating field of science." - }, - { - "Title":"Handbook of Positive Psychology", - "Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind." - }, - { - "Title":"Psychology of Sustainable Development", - "Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment." - }, - { - "Title":"An Introduction to the History of Psychology", - "Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years." - }, - { - "Title":"Careers in Psychology: Opportunities in a Changing World", - "Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level." - }, - { - "Title":"Philosophy of Psychology", - "Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class." - }, - { - "Title":"The Psychology of Risk Taking Behavior", - "Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship." - }, - { - "Title":"Legal Notices", - "Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version." - }, - { - "Title":"Handbook of Psychology, Experimental Psychology", - "Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area." - }, - { - "Title":"Culture and Psychology", - "Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today." - }, - { - "Title":"Exploring the Psychology of Interest", - "Text":"The most comprehensive work of its kind, Exploring the Psychology of Interest will be a valuable resource for student and professional researchers in cognitive, social, and developmental psychology." - }, - { - "Title":"Handbook of Adolescent Psychology", - "Text":"The study of adolescence in the field of psychology has grown tremendously over the last two decades, necessitating a comprehensive and up-to-date revision of this seminal work." - }, - { - "Title":"The Psychology of Diplomacy", - "Text":"World class clinicians, researchers, and activists present the psychological dimensions to diplomacy drawn from examples set in the United Nations, Camp David, the Middle East, Japan, South Africa, and elsewhere." - }, - { - "Title":"The Psychology of Social Class", - "Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery." - }, - { - "Title":"Popular Psychology: An Encyclopedia", - "Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder." - }, - { - "Title":"E-Z Psychology", - "Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know." - }, - { - "Title":"Psychology and Health", - "Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know." - }, - { - "Title":"Influence", - "Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion." - }, - { - "Title":"Psychology and Policing", - "Text":"The book should draw attention to the often unrecognized and valuable contribution that mainstream psychology can make to the knowledge base underpinning a wide variety of policing practices." - }, - { - "Title":"Applied Psychology: New Frontiers and Rewarding Careers", - "Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change." - }, - { - "Title":"Foundations of Sport and Exercise Psychology, 6E: ", - "Text":"This text offers both students and new practitioners a comprehensive view of sport and exercise psychology, drawing connections between research and practice and capturing the excitement of the world of sport and exercise." - }, - { - "Title":"Biographical Dictionary of Psychology", - "Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured." - }, - { - "Title":"Psychology: A Self-Teaching Guide", - "Text":"Frank Bruno explains all the major psychological theories and terms in this book, covering perception, motivation, thinking, personality, sensation, intelligence, research methods, and much more." - }, - { - "Title":"A Dictionary of Psychology", - "Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text." - }, - { - "Title":"darbian regarding how fast you can learn to speedrun", - "Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice." - }, - { - "Title":"Memes", - "Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start." - }, - { - "Title":"Literature quotes", - "Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare" - }, - { - "Title":"Literature quotes", - "Text":"All generalizations are false, including this one. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett" - }, - { - "Title":"Literature quotes", - "Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain" - }, - { - "Title":"Literature quotes", - "Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats" - }, - { - "Title":"Pat Cadigan, \"Mindplayers\"", - "Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque." - }, - { - "Title":"Men & Women", - "Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\"" - }, - { - "Title":"James L. Collymore, \"Perfect Woman\"", - "Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time." - }, - { - "Title":"Famous quotes", - "Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln" - }, - { - "Title":"Men & Women", - "Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\"" - }, - { - "Title":"Encyclopadia Apocryphia, 1990 ed.", - "Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course." - }, - { - "Title":"Susan Gordon", - "Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort." - }, - { - "Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"", - "Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations." - }, - { - "Title":"Medicine", - "Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment." - }, - { - "Title":"Medicine", - "Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize." - }, - { - "Title":"The C Programming Language", - "Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation." - }, - { - "Title":"Religious Texts", - "Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12" - }, - { - "Title":"Religious Texts", - "Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi" - }, - { - "Title":"Religious Texts", - "Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85" - }, - { - "Title":"Religious Texts", - "Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13" - }, - { - "Title":"Religious Texts", - "Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18" - }, - { - "Title":"Religious Texts", - "Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis" - }, - { - "Title":"Medicine", - "Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry" - }, - { - "Title":"Medicine", - "Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps" - }, - { - "Title":"Medicine", - "Text":"Never go to a doctor whose office plants have died -- Erma Bombeck" - }, - { - "Title":"Science", - "Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\"" - }, - { - "Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"", - "Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track." - }, - { - "Title":"#Octalthorpe", - "Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on." - }, - { - "Title":"Science -- Edgar R. Fiedler", - "Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor." - }, - { - "Title":"Science -- R. Buckminster Fuller", - "Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines." - }, - { - "Title":"Math", - "Text":"Factorials were someone's attempt to make math LOOK exciting." - }, - { - "Title":"Science -- Thomas L. Creed", - "Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence." - }, - { - "Title":"Science -- H. L. Mencken, 1930", - "Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable." - }, - { - "Title":"Science", - "Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe." - }, - { - "Title":"Science -- Stanislaw Lem", - "Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..." - }, - { - "Title":"Science -- Dave Barry", - "Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily." - }, - { - "Title":"Sports", - "Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry" - }, - { - "Title":"Sports", - "Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel" - }, - { - "Title":"Sports", - "Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out." - }, - { - "Title":"Sports", - "Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali" - }, - { - "Title":"Sports", - "Text":"The surest way to remain a winner is to win once, and then not play any more." - }, - { - "Title":"Sports", - "Text":"The real problem with hunting elephants is carrying the decoys" - }, - { - "Title":"Sports -- Dizzy Dean", - "Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it." - }, - { - "Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium", - "Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now." - }, - { - "Title":"Sports", - "Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand." - }, - { - "Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"", - "Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical." - }, - { - "Title":"Smart House", - "Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman" - }, - { - "Title":"Linux -- Jim Wright", - "Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!" - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software." - }, - { - "Title":"True Words of a Genius Philosopher", - "Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society." - }, - { - "Title":"Politics -- Donald Trump", - "Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people." - }, - { - "Title":"Politics -- Sir Winston Churchill, 1952", - "Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him." - }, - { - "Title":"Politics -- Johnny Hart", - "Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation." - }, - { - "Title":"Politics -- Winston Churchill", - "Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time." - }, - { - "Title":"Politics", - "Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record." - }, - { - "Title":"Politics -- A Yippie Proverb", - "Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire." - }, - { - "Title":"Politics -- Boss Tweed", - "Text":"I don't care who does the electing as long as I get to do the nominating." - }, - { - "Title":"Politics -- Francis Bellamy, 1892", - "Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all." - }, - { - "Title":"Politics -- Napoleon", - "Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall." - }, - { - "Title":"Politics", - "Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away." - }, - { - "Title":"Politics -- Frederick Douglass", - "Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains." - }] diff --git a/src/NadekoBot/data/typing_articles2.json b/src/NadekoBot/data/typing_articles2.json new file mode 100644 index 00000000..78214ea2 --- /dev/null +++ b/src/NadekoBot/data/typing_articles2.json @@ -0,0 +1 @@ +[{"Title":"The Gender of Psychology","Text":"This book addresses the diversity of psychological knowledge and practice through the lens of gender."},{"Title":"Unto Others: The Evolution and Psychology of Unselfish","Text":"In Unto Others philosopher Elliott Sober and biologist David Sloan Wilson demonstrate once and for all that unselfish behavior is in fact an important feature of both biological and human nature."},{"Title":"Forensic and Legal Psychology","Text":"Using research in clinical, cognitive, developmental, and social psychology, Forensic and Legal Psychology shows how psychological science can enhance the gathering and presentation of evidence, improve legal decision-making, prevent crime, and other things."},{"Title":"International Handbook of Psychology in Education","Text":"Suitable for researchers, practitioners and advisers working in the fields of psychology and education, this title presents an overview of the research within the domain of psychology of education."},{"Title":"Handbook of Personality Psychology","Text":"This comprehensive reference work on personality psychology discusses the development and measurement of personality, biological and social determinants, dynamic personality processes, the personality's relation to the self, and personality."},{"Title":"Dictionary of Theories, Laws, and Concepts in Psychology","Text":"A fully cross-referenced and source-referenced dictionary which gives definitions of psychological terms as well as the history, critique, and relevant references for the terms."},{"Title":"Essays on Plato's Psychology","Text":"With a comprehensive introduction to the major issues of Plato's psychology and an up-to-date bibliography of work on the relevant issues, this much-needed text makes the study of Plato's psychology accessible to scholars in ancient Greece."},{"Title":"A History of Psychology","Text":"First published in 2002. Routledge is an imprint of Taylor & Francis, an informa company."},{"Title":"An Introduction to the Psychology of Religion","Text":"The third edition of this successful book, which applies the science of psychology to problems of religion. Dr Thouless explores such questions as: why do people believe? Why are their beliefs often held with irrational strength?"},{"Title":"Psychology of Champions: How to Win at Sports and Life","Text":"In this unprecedented book, two psychologist researchers interview sports legends and super-athletes across sports to explain the thinking that powers stellar performers, pushing them to amazing and historic successes."},{"Title":"The Psychology of Humor: An Integrative Approach","Text":"This is a singly authored monograph that provides in one source, a summary of information researchers might wish to know about research into the psychology of humor."},{"Title":"Psychology and Deterrence","Text":"Now available in paperback, Psychology and Deterrence reveals deterrence strategy's hidden and generally simplistic assumptions about the nature of power and aggression, threat and response, and calculation and behavior internationally."},{"Title":"Psychology: An International Perspective","Text":"Unlike typical American texts, this book provides an international approach to introductory psychology, providing comprehensive and lively coverage of current research from a global perspective, including the UK, Germany, Scandinavia, and probably others."},{"Title":"Psychology, Briefer Course","Text":"Despite its title, \"Psychology: Briefer Course\" is more than a simple condensation of the great Principles of Psychology."},{"Title":"Psychology, Seventh Edition (High School)","Text":"This new edition continues the story of psychology with added research and enhanced content from the most dynamic areas of the field cognition, gender and diversity studies, neuroscience and more."},{"Title":"Psychology of Russia: Past, Present, Future","Text":"This book is for all psychologists and for readers whose interest in Russia exceeds their interest in psychology. Readers of this book will quickly discover a new world of thought."},{"Title":"Barron's AP Psychology","Text":"Provides information on scoring and structure of the test, offers tips on test-taking strategies, and includes practice examinations and subject review."},{"Title":"Applied Psychology: Putting Theory Into Practice","Text":"Applied Psychology: Putting theory into practice demonstrates how psychology theory is applied in the real world."},{"Title":"Filipino American Psychology: A Handbook of Theory,","Text":"This book is the first of its kind and aims to promote visibility of this invisible group, so that 2.4 million Filipino Americans will have their voices heard."},{"Title":"The Psychology of Visual Illusion","Text":"Well-rounded perspective on the ambiguities of visual display emphasizes geometrical optical illusions: framing and contrast effects, distortion of angles and direction, and apparent \"movement\" of images. 240 drawings. 1972 edition."},{"Title":"The Psychology of Women","Text":"This highly respected text offers students an enjoyable, extraordinarily well-written introduction to the psychology of women with an up-to-date examination of the field and comprehensive coverage of topics."},{"Title":"Psychology and Race","Text":"Psychology and Race is divided into two major parts. The first half of the book looks at the interracial situation itself. The second half is a mystery."},{"Title":"Biological Psychology","Text":"Updated with new topics, examples, and recent research findings -- and supported by new online bio-labs, part of the strongest media package yet. This text speaks to today's students and instructors."},{"Title":"Psychology: Concepts & Connections","Text":"The theme of this book is applying theories and research to learning and to contemporary life."},{"Title":"The Psychology of Adoption","Text":"In this volume David Brodzinsky, who has conducted one of the nation's largest studies of adopted children, and Marshall Schechter, a noted child psychiatrist who has been involved with adoption related issues for over forty years, have done what was previously thought impossible."},{"Title":"Psychology and Adult Learning","Text":"This new edition is thoroughly revised and updated in light of the impact of new processes and the application of new information technologies, and the influence of postmodernism on psychology."},{"Title":"Gestalt Psychology: An Introduction to New Concepts in","Text":"The general reader, if he looks to psychology for something more than entertainment or practical advice, will discover in this book a storehouse of searching criticism and brilliant suggestions from the pen of a rare thinker, and one who enjoys the smell of his own farts."},{"Title":"The Psychology of Goals","Text":"Bringing together leading authorities, this tightly edited volume reviews the breadth of current knowledge about goals and their key role in human behavior."},{"Title":"Metaphors in the History of Psychology","Text":"Through the identification of these metaphors, the contributors to this volume have provided a remarkably useful guide to the history, current orientations, and future prospects of modern psychology."},{"Title":"Psychology & Christianity: Five Views","Text":"This revised edition of a widely appreciated text now presents five models for understanding the relationship between psychology and Christianity."},{"Title":"The Psychology of Hope: You Can Get There from Here","Text":"Why do some people lead positive, hope-filled lives, while others wallow in pessimism? In \"The Psychology of Hope\", a professor of psychology reveals the specific character traits that produce highly hopeful individuals."},{"Title":"Perspectives on Psychology","Text":"This is a title in the modular \"Principles in Psychology Series\", designed for A-level and other introductory courses, aiming to provide students embarking on psychology courses with the necessary background and context."},{"Title":"Ethics in Psychology: Professional Standards and Cases","Text":"In this book, their main intent is to present the full range of contemporary ethical issues in psychology as not only relevant and intriguing, but also as integral and unavoidable aspects of the profession."},{"Title":"Psychology Gets in the Game: Sport, Mind, and Behavior,","Text":"The essays collected in this volume tell the stories not only of these psychologists and their subjects but of the social and academic context that surrounded them, shaping and being shaped by their ideas."},{"Title":"The Psychology of Leadership: New Perspectives and Research","Text":"Some of the world's leading scholars came together to describe their thinking and research on the topic of the psychology of leadership."},{"Title":"The Psychology of Interpersonal Relations","Text":"As the title suggests, this book examines the psychology of interpersonal relations. In the context of this book, the term \"interpersonal relations\" denotes relations between a few, usually between two, people."},{"Title":"Psychology","Text":"An exciting read for anyone interested in psychology and research; because of its comprehensive appendix, glossary, and reference section, this book is a must-have desk reference for psychologists and others in the field."},{"Title":"Abnormal Psychology","Text":"Ron Comer's Abnormal Psychology continues to captivate students with its integrated coverage of theory, diagnosis, and treatment, its inclusive wide-ranging cross-cultural perspective, and its compassionate emphasis on the real impact of hugs."},{"Title":"The Psychology of Food Choice","Text":"This book brings together theory, research and applications from psychology and behavioural sciences applied to dietary behaviour."},{"Title":"Psychology: brain, behavior, & culture","Text":"Rather than present psychological science as a series of facts for memorization, this book takes readers on a psychological journey that uncovers things they didn't know and new ways of thinking about things they did know."},{"Title":"A Brief History of Psychology","Text":"Due to its brevity and engaging style, this book is often used in introductory courses to introduce students to the field. The enormous index and substantial glossary make this volume a useful desk reference for the entire field."},{"Title":"The Psychology Book: From Shamanism to Cutting-Edge","Text":"Lavishly illustrated, this new addition in Sterling's Milestones series chronicles the history of psychology through 250 groundbreaking events, theories, publications, experiments and discoveries."},{"Title":"The Psychology Book","Text":"All the big ideas, simply explained - an innovative and accessible guide to the study of human nature The Psychology Book clearly explains more than 100 groundbreaking ideas in this fascinating field of science."},{"Title":"Handbook of Positive Psychology","Text":"The Handbook of Positive Psychology provides a forum for a more positive view of the human condition. In its pages, readers are treated to an analysis of what the foremost experts believe to be the fundamental strengths of humankind."},{"Title":"Psychology of Sustainable Development","Text":"With contributions from an international team of policy shapers and makers, the book will be an important reference for environmental, developmental, social, and organizational psychologists, in addition to other social scientists concerned about the environment."},{"Title":"An Introduction to the History of Psychology","Text":"In this Fifth Edition, B.R. Hergenhahn demonstrates that most of the concerns of contemporary psychologists are manifestations of themes that have been part of psychology for thousands of years."},{"Title":"Careers in Psychology: Opportunities in a Changing World","Text":"This text addresses the growing need among students and faculty for information about the careers available in psychology at the bachelors and graduate level."},{"Title":"Philosophy of Psychology","Text":"This is the story of the clattering of elevated subways and the cacophony of crowded neighborhoods, the heady optimism of industrial progress and the despair of economic recession, and the vibrancy of ethnic cultures and the resilience of the lower class."},{"Title":"The Psychology of Risk Taking Behavior","Text":"This book aims to help the reader to understand what motivates people to engage in risk taking behavior, such as participating in traffic, sports, financial investments, or courtship."},{"Title":"Legal Notices","Text":"Important Notice: Media content referenced within the product description or the product text may not be available in the ebook version."},{"Title":"Handbook of Psychology, Experimental Psychology","Text":"Includes established theories and cutting-edge developments. Presents the work of an international group of experts. Presents the nature, origin, implications, and future course of major unresolved issues in the area."},{"Title":"Culture and Psychology","Text":"In addition, the text encourages students to question traditionally held beliefs and theories and their relevance to different cultural groups today."},{"Title":"Exploring the Psychology of Interest","Text":"The most comprehensive work of its kind, Exploring the Psychology of Interest will be a valuable resource for student and professional researchers in cognitive, social, and developmental psychology."},{"Title":"Handbook of Adolescent Psychology","Text":"The study of adolescence in the field of psychology has grown tremendously over the last two decades, necessitating a comprehensive and up-to-date revision of this seminal work."},{"Title":"The Psychology of Diplomacy","Text":"World class clinicians, researchers, and activists present the psychological dimensions to diplomacy drawn from examples set in the United Nations, Camp David, the Middle East, Japan, South Africa, and elsewhere."},{"Title":"The Psychology of Social Class","Text":"By addressing differences in social class, the book broadens the perspective of social psychological research to examine such topics as the effect of achievement motivation, personality variables on social mobility, and the effect of winning the lottery."},{"Title":"Popular Psychology: An Encyclopedia","Text":"Entries cover a variety of topics in the field of popular psychology, including acupuncture, emotional intelligence, brainwashing, chemical inbalance, and seasonal affective disorder."},{"Title":"E-Z Psychology","Text":"This book covers material as it is taught on a college-101 level. There is no substance in this book that the casual observer of humans would not already know."},{"Title":"Psychology and Health","Text":"Part of a series of textbooks which have been written to support A levels in psychology. The books use real life applications to make theories come alive for students and teach them what they need to know."},{"Title":"Influence","Text":"Influence is the classic book on persuasion. It explains the psychology of why people say 'yes' and how to apply these understandings. Dr. Robert Cialdini is the seminal expert in the rapidly expanding field of influence and persuasion."},{"Title":"Psychology and Policing","Text":"The book should draw attention to the often unrecognized and valuable contribution that mainstream psychology can make to the knowledge base underpinning a wide variety of policing practices."},{"Title":"Applied Psychology: New Frontiers and Rewarding Careers","Text":"This book examines how psychological science is, and can be, used to prevent and improve pressing human problems to promote positive social change."},{"Title":"Foundations of Sport and Exercise Psychology, 6E: ","Text":"This text offers both students and new practitioners a comprehensive view of sport and exercise psychology, drawing connections between research and practice and capturing the excitement of the world of sport and exercise."},{"Title":"Biographical Dictionary of Psychology","Text":"This dictionary provides biographical and bibliographical information on over 500 psychologists from all over the world from 1850 to the present day. All branches of psychology and its related disciplines are featured."},{"Title":"Psychology: A Self-Teaching Guide","Text":"Frank Bruno explains all the major psychological theories and terms in this book, covering perception, motivation, thinking, personality, sensation, intelligence, research methods, and much more."},{"Title":"A Dictionary of Psychology","Text":"Entries are extensively cross-referenced for ease of use, and cover word origins and derivations as well as definitions. Over 80 illustrations complement the text."},{"Title":"darbian regarding how fast you can learn to speedrun","Text":"This depends on a number of factors. The answer will be very different for someone who doesn't have a lot of experience with videogames compared to someone who is already decent at retro platformers. In my case, it took about a year of playing on and off to get pretty competitive at the game, but there have been others who did it much faster. With some practice you can get a time that would really impress your friends after only a few days of practice."},{"Title":"Memes","Text":"The FitnessGram Pacer Test is a multistage aerobic capacity test that progressively gets more difficult as it continues. The 20 meter pacer test will begin in 30 seconds. Line up at the start. The running speed starts slowly, but gets faster each minute after you hear this signal. [beep] A single lap should be completed each time you hear this sound. [ding] Remember to run in a straight line, and run as long as possible. The second time you fail to complete a lap before the sound, your test is over. The test will begin on the word start. On your mark, get ready, start."},{"Title":"Literature quotes","Text":"A banker is a fellow who lends you his umbrella when the sun is shining and wants it back the minute it begins to rain. -- Mark Twain"},{"Title":"Literature quotes","Text":"A classic is something that everyone wants to have read and nobody wants to read. -- Mark Twain"},{"Title":"Literature quotes","Text":"After all, all he did was string together a lot of old, well-known quotations. -- H. L. Mencken, on Shakespeare"},{"Title":"Literature quotes","Text":"All generalizations are false, including this one. -- Mark Twain"},{"Title":"Literature quotes","Text":"All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. -- Samuel Beckett"},{"Title":"Literature quotes","Text":"All say, \"How hard it is that we have to die\" -- a strange complaint to come from the mouths of people who have had to live. -- Mark Twain"},{"Title":"Literature quotes","Text":"At once it struck me what quality went to form a man of achievement, especially in literature, and which Shakespeare possessed so enormously -- I mean negative capability, that is, when a man is capable of being in uncertainties, mysteries, doubts, without any irritable reaching after fact and reason. -- John Keats"},{"Title":"Pat Cadigan, \"Mindplayers\"","Text":"A morgue is a morgue is a morgue. They can paint the walls with aggressively cheerful primary colors and splashy bold graphics, but it's still a holding place for the dead until they can be parted out to organ banks. Not that I would have cared normally but my viewpoint was skewed. The relentless pleasance of the room I sat in seemed only grotesque."},{"Title":"Men & Women","Text":"A diplomatic husband said to his wife, \"How do you expect me to remember your birthday when you never look any older?\""},{"Title":"James L. Collymore, \"Perfect Woman\"","Text":"I began many years ago, as so many young men do, in searching for the perfect woman. I believed that if I looked long enough, and hard enough, I would find her and then I would be secure for life. Well, the years and romances came and went, and I eventually ended up settling for someone a lot less than my idea of perfection. But one day, after many years together, I lay there on our bed recovering from a slight illness. My wife was sitting on a chair next to the bed, humming softly and watching the late afternoon sun filtering through the trees. The only sounds to be heard elsewhere were the clock ticking, the kettle downstairs starting to boil, and an occasional schoolchild passing beneath our window. And as I looked up into my wife's now wrinkled face, but still warm and twinkling eyes, I realized something about perfection... It comes only with time."},{"Title":"Famous quotes","Text":"I have now come to the conclusion never again to think of marrying, and for this reason: I can never be satisfied with anyone who would be blockhead enough to have me. -- Abraham Lincoln"},{"Title":"Men & Women","Text":"In the midst of one of the wildest parties he'd ever been to, the young man noticed a very prim and pretty girl sitting quietly apart from the rest of the revelers. Approaching her, he introduced himself and, after some quiet conversation, said, \"I'm afraid you and I don't really fit in with this jaded group. Why don't I take you home?\" \"Fine,\" said the girl, smiling up at him demurely. \"Where do you live?\""},{"Title":"Encyclopadia Apocryphia, 1990 ed.","Text":"There is no realizable power that man cannot, in time, fashion the tools to attain, nor any power so secure that the naked ape will not abuse it. So it is written in the genetic cards -- only physics and war hold him in check. And also the wife who wants him home by five, of course."},{"Title":"Susan Gordon","Text":"What publishers are looking for these days isn't radical feminism. It's corporate feminism -- a brand of feminism designed to sell books and magazines, three-piece suits, airline tickets, Scotch, cigarettes and, most important, corporate America's message, which runs: Yes, women were discriminated against in the past, but that unfortunate mistake has been remedied; now every woman can attain wealth, prestige and power by dint of individual rather than collective effort."},{"Title":"Susan Bolotin, \"Voices From the Post-Feminist Generation\"","Text":"When my freshman roommate at Cornell found out I was Jewish, she was, at her request, moved to a different room. She told me she didn't think she had ever seen a Jew before. My only response was to begin wearing a small Star of David on a chain around my neck. I had not become a more observing Jew; rather, discovering that the label of Jew was offensive to others made me want to let people know who I was and what I believed in. Similarly, after talking to these young women -- one of whom told me that she didn't think she had ever met a feminist -- I've taken to identifying myself as a feminist in the most unlikely of situations."},{"Title":"Medicine","Text":"Never die while in your doctor's prescence or under his direct care. This will only cause him needless inconvenience and embarassment."},{"Title":"Medicine","Text":"Human cardiac catheterization was introduced by Werner Forssman in 1929. Ignoring his department chief, and tying his assistant to an operating table to prevent her interference, he placed a ureteral catheter into a vein in his arm, advanced it to the right atrium [of his heart], and walked upstairs to the x-ray department where he took the confirmatory x-ray film. In 1956, Dr. Forssman was awarded the Nobel Prize."},{"Title":"The C Programming Language","Text":"In Chapter 3 we presented a Shell sort function that would sort an array of integers, and in Chapter 4 we improved on it with a quicksort. The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation."},{"Title":"Religious Texts","Text":"O ye who believe! Avoid suspicion as much (as possible): for suspicion in some cases in a sin: And spy not on each other behind their backs. Quran 49:12"},{"Title":"Religious Texts","Text":"If you want to destroy any nation without war, make adultery & nudity common in the next generation. -- Salahuddin Ayyubi"},{"Title":"Religious Texts","Text":"Whoever recommends and helps a good cause becomes a partner therein, and whoever recommends and helps an evil cause shares in its burdens. Quran 4:85"},{"Title":"Religious Texts","Text":"No servant can serve two masters. Either he will hate the one and love the other, or he will be devoted to the one and despise the other. You cannot serve both God and Money. Luke 16:13"},{"Title":"Religious Texts","Text":"So we do not lose heart. Though our outer man is wasting away, our inner self is being renewed day by day. For this light momentary affliction is preparing for us an eternal weight of glory beyond all comparison, as we look not to the things that are seen but to the things that are unseen. For the things that are seen are transient, but the things that are unseen are eternal. 2 Corinthians 4:16-18"},{"Title":"Religious Texts","Text":"And out of that hopeless attempt has come nearly all that we call human history -- money, poverty, ambition, war, prostitution, classes, empires, slavery -- the long terrible story of man trying to find something other than God which will make him happy. -- C.S. Lewis"},{"Title":"Medicine","Text":"Your digestive system is your body's Fun House, whereby food goes on a long, dark, scary ride, taking all kinds of unexpected twists and turns, being attacked by vicious secretions along the way, and not knowing until the last minute whether it will be turned into a useful body part or ejected into the Dark Hole by Mister Sphincter. We Americans live in a nation where the medical-care system is second to none in the world, unless you count maybe 25 or 30 little scuzzball countries like Scotland that we could vaporize in seconds if we felt like it. -- Dave Barry"},{"Title":"Medicine","Text":"The trouble with heart disease is that the first symptom is often hard to deal with: death. -- Michael Phelps"},{"Title":"Medicine","Text":"Never go to a doctor whose office plants have died -- Erma Bombeck"},{"Title":"Science","Text":"Albert Einstein, when asked to describe radio, replied: \"You see, wire telegraph is a kind of a very, very long cat. You pull his tail in NewYork and his head is meowing in Los Angeles. Do you understand this? And radio operates exactly the same way: you send signals here, they receive them there. The only difference is that there is no cat.\""},{"Title":"Carl Sagan, \"The Fine Art of Baloney Detection\"","Text":"At the heart of science is an essential tension between two seemingly contradictory attitudes -- an openness to new ideas, no matter how bizarre or counterintuitive they may be, and the most ruthless skeptical scrutiny of all ideas, old and new. This is how deep truths are winnowed from deep nonsense. Of course, scientists make mistakes in trying to understand the world, but there is a built-in error-correcting mechanism: The collective enterprise of creative thinking and skeptical thinking together keeps the field on track."},{"Title":"#Octalthorpe","Text":"Back in the early 60's, touch tone phones only had 10 buttons. Some military versions had 16, while the 12 button jobs were used only by people who had \"diva\" (digital inquiry, voice answerback) systems -- mainly banks. Since in those days, only Western Electric made \"data sets\" (modems) the problems of terminology were all Bell System. We used to struggle with written descriptions of dial pads that were unfamiliar to most people (most phones were rotary then.) Partly in jest, some AT&T engineering types (there was no marketing in the good old days, which is why they were the good old days) made up the term \"octalthorpe\" (note spelling) to denote the \"pound sign.\" Presumably because it has 8 points sticking out. It never really caught on."},{"Title":"Science -- Edgar R. Fiedler","Text":"Economists state their GDP growth projections to the nearest tenth of a percentage point to prove they have a sense of humor."},{"Title":"Science -- R. Buckminster Fuller","Text":"Everything you've learned in school as \"obvious\" becomes less and less obvious as you begin to study the universe. For example, there are no solids in the universe. There's not even a suggestion of a solid. There are no absolute continuums. There are no surfaces. There are no straight lines."},{"Title":"Math","Text":"Factorials were someone's attempt to make math LOOK exciting."},{"Title":"Science -- Thomas L. Creed","Text":"Fortunately, the responsibility for providing evidence is on the part of the person making the claim, not the critic. It is not the responsibility of UFO skeptics to prove that a UFO has never existed, nor is it the responsibility of paranormal-health-claims skeptics to prove that crystals or colored lights never healed anyone. The skeptic's role is to point out claims that are not adequately supported by acceptable evidcence and to provide plausible alternative explanations that are more in keeping with the accepted body of scientific evidence."},{"Title":"Science -- H. L. Mencken, 1930","Text":"There is, in fact, no reason to believe that any given natural phenomenon, however marvelous it may seem today, will remain forever inexplicable. Soon or late the laws governing the production of life itself will be discovered in the laboratory, and man may set up business as a creator on his own account. The thing, indeed, is not only conceivable; it is even highly probable."},{"Title":"Science","Text":"When Alexander Graham Bell died in 1922, the telephone people interrupted service for one minute in his honor. They've been honoring him intermittently ever since, I believe."},{"Title":"Science -- Stanislaw Lem","Text":"When the Universe was not so out of whack as it is today, and all the stars were lined up in their proper places, you could easily count them from left to right, or top to bottom, and the larger and bluer ones were set apart, and the smaller yellowing types pushed off to the corners as bodies of a lower grade..."},{"Title":"Science -- Dave Barry","Text":"You should not use your fireplace, because scientists now believe that, contrary to popular opinion, fireplaces actually remove heat from houses. Really, that's what scientists believe. In fact many scientists actually use their fireplaces to cool their houses in the summer. If you visit a scientist's house on a sultry August day, you'll find a cheerful fire roaring on the hearth and the scientist sitting nearby, remarking on how cool he is and drinking heavily."},{"Title":"Sports","Text":"Although golf was originally restricted to wealthy, overweight Protestants, today it's open to anybody who owns hideous clothing. -- Dave Barry"},{"Title":"Sports","Text":"Now there's three things you can do in a baseball game: you can win, you can lose, or it can rain. -- Casey Stengel"},{"Title":"Sports","Text":"Once there was this conductor see, who had a bass problem. You see, during a portion of Beethovan's Ninth Symphony in which there are no bass violin parts, one of the bassists always passed a bottle of scotch around. So, to remind himself that the basses usually required an extra cue towards the end of the symphony, the conductor would fasten a piece of string around the page of the score before the bass cue. As the basses grew more and more inebriated, two of them fell asleep. The conductor grew quite nervous (he was very concerned about the pitch) because it was the bottom of the ninth; the score was tied and the basses were loaded with two out."},{"Title":"Sports","Text":"When I'm gone, boxing will be nothing again. The fans with the cigars and the hats turned down'll be there, but no more housewives and little men in the street and foreign presidents. It's goin' to be back to the fighter who comes to town, smells a flower, visits a hospital, blows a horn and says he's in shape. Old hat. I was the onliest boxer in history people asked questions like a senator. -- Muhammad Ali"},{"Title":"Sports","Text":"The surest way to remain a winner is to win once, and then not play any more."},{"Title":"Sports","Text":"The real problem with hunting elephants is carrying the decoys"},{"Title":"Sports -- Dizzy Dean","Text":"The pitcher wound up and he flang the ball at the batter. The batter swang and missed. The pitcher flang the ball again and this time the batter connected. He hit a high fly right to the center fielder. The center fielder was all set to catch the ball, but at the last minute his eyes were blound by the sun and he dropped it."},{"Title":"Sports -- Babe Ruth, in his 1948 farewell speech at Yankee Stadium","Text":"The only real game in the world, I think, is baseball... You've got to start way down, at the bottom, when you're six or seven years old. You can't wait until you're fifteen or sixteen. You've got to let it grow up with you, and if you're successful and you try hard enough, you're bound to come out on top, just like these boys have come to the top now."},{"Title":"Sports","Text":"The one sure way to make a lazy man look respectable is to put a fishing rod in his hand."},{"Title":"Linux -- Linus Torvalds in response to \"Other than the fact Linux has a cool name, could someone explain why I should use Linux over BSD?\"","Text":"No. That's it. The cool name, that is. We worked very hard on creating a name that would appeal to the majority of people, and it certainly paid off: thousands of people are using linux just to be able to say \"OS/2? Hah. I've got Linux. What a cool name\". 386BSD made the mistake of putting a lot of numbers and weird abbreviations into the name, and is scaring away a lot of people just because it sounds too technical."},{"Title":"Smart House","Text":"A teenager wins a fully automated dream house in a competition, but soon the computer controlling it begins to take over and everything gets out of control, then Ben the teenager calms down the computer named Pat and everything goes back to normal."},{"Title":"True Words of a Genius Philosopher","Text":"Writing non-free software is not an ethically legitimate activity, so if people who do this run into trouble, that's good! All businesses based on non-free software ought to fail, and the sooner the better. -- Richard Stallman"},{"Title":"Linux -- Jim Wright","Text":"You know, if Red Hat was smart, they'd have a fake front on their office building just for visitors, where you would board a magical trolley that took you past the smiling singing oompah loompahs who take the raw linux sugar and make it into Red Hat candy goodness. Then they could use it as a motivator for employees... Shape up, or you're spending time working \"the ride\"!"},{"Title":"True Words of a Genius Philosopher","Text":"Free software is software that gives you the user the freedom to share, study and modify it. We call this free software because the user is free."},{"Title":"True Words of a Genius Philosopher","Text":"To use free software is to make a political and ethical choice asserting the right to learn, and share what we learn with others. Free software has become the foundation of a learning society where we share our knowledge in a way that others can build upon and enjoy."},{"Title":"True Words of a Genius Philosopher","Text":"Currently, many people use proprietary software that denies users these freedoms and benefits. If we make a copy and give it to a friend, if we try to figure out how the program works, if we put a copy on more than one of our own computers in our own home, we could be caught and fined or put in jail. That's what's in the fine print of the license agreement you accept when using proprietary software."},{"Title":"True Words of a Genius Philosopher","Text":"The corporations behind proprietary software will often spy on your activities and restrict you from sharing with others. And because our computers control much of our personal information and daily activities, proprietary software represents an unacceptable danger to a free society."},{"Title":"Politics -- Donald Trump","Text":"When Mexico sends its people, they're not sending their best. They're not sending you. They're sending people that have lots of problems, and they're bringing those problems with us. They're bringing drugs. They're bringing crime. Their rapists. And some, I assume, are good people."},{"Title":"Politics -- Sir Winston Churchill, 1952","Text":"A prisoner of war is a man who tries to kill you and fails, and then asks you not to kill him."},{"Title":"Politics -- Johnny Hart","Text":"Cutting the space budget really restores my faith in humanity. It eliminates dreams, goals, and ideals and lets us get straight to the business of hate, debauchery, and self-annihilation."},{"Title":"Politics -- Winston Churchill","Text":"Democracy is the worst form of government except all those other forms that have been tried from time to time."},{"Title":"Politics","Text":"Each person has the right to take part in the management of public affairs in his country, provided he has prior experience, a will to succeed, a university degree, influential parents, good looks, a curriculum vitae, two 3x4 snapshots, and a good tax record."},{"Title":"Politics -- A Yippie Proverb","Text":"Free Speech Is The Right To Shout 'Theater' In A Crowded Fire."},{"Title":"Politics -- Boss Tweed","Text":"I don't care who does the electing as long as I get to do the nominating."},{"Title":"Politics -- Francis Bellamy, 1892","Text":"I pledge allegiance to the flag of the United States of America and to the republic for which it stands, one nation, indivisible, with liberty and justice for all."},{"Title":"Politics -- Napoleon","Text":"It follows that any commander in chief who undertakes to carry out a plan which he considers defective is at fault; he must put forth his reasons, insist of the plan being changed, and finally tender his resignation rather than be the instrument of his army's downfall."},{"Title":"Politics","Text":"Only two kinds of witnesses exist. The first live in a neighborhood where a crime has been committed and in no circumstances have ever seen anything or even heard a shot. The second category are the neighbors of anyone who happens to be accused of the crime. These have always looked out of their windows when the shot was fired, and have noticed the accused person standing peacefully on his balcony a few yards away."},{"Title":"Politics -- Frederick Douglass","Text":"Slaves are generally expected to sing as well as to work ... I did not, when a slave, understand the deep meanings of those rude, and apparently incoherent songs. I was myself within the circle, so that I neither saw nor heard as those without might see and hear. They told a tale which was then altogether beyond my feeble comprehension: they were tones, loud, long and deep, breathing the prayer and complaint of souls boiling over with the bitterest anguish. Every tone was a testimony against slavery, and a prayer to God for deliverance from chains."}] \ No newline at end of file From e982b0fc1895ffbeb5fa465e77e20c06946728c3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 10:56:51 +0200 Subject: [PATCH 06/26] forgot to up the version --- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index ba0f5e37..f18845ad 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Impl private readonly DiscordShardedClient _client; private readonly DateTime _started; - public const string BotVersion = "1.26"; + public const string BotVersion = "1.26a"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; From ca05b14f3e1e0da07f10e79256cb3e868ac9cb19 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Tue, 28 Mar 2017 11:56:31 +0200 Subject: [PATCH 07/26] Updated commandlist --- docs/Commands List.md | 130 ++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 1317f263..0ce3438d 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -1,6 +1,6 @@ You can support the project on patreon: or paypal: -##Table Of Contents +##Table of contents - [Help](#help) - [Administration](#administration) - [ClashOfClans](#clashofclans) @@ -16,7 +16,7 @@ You can support the project on patreon: or paypa ### Administration -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `.resetperms` | Resets the bot's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` `.delmsgoncmd` | Toggles the automatic deletion of the user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` @@ -40,27 +40,27 @@ Command and aliases | Description | Usage `.prune` `.clr` | `.prune` removes all Nadeko's messages in the last 100 messages. `.prune X` removes last `X` number of messages from the channel (up to 100). `.prune @Someone` removes all Someone's messages in the last 100 messages. `.prune @Someone X` removes last `X` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` `.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have the mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` `.donators` | List of the lovely people who donated to keep this project alive. | `.donators` -`.donadd` | Add a donator to the database. **Bot Owner Only** | `.donadd Donate Amount` +`.donadd` | Add a donator to the database. **Bot owner only** | `.donadd Donate Amount` `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable `.languageset` `.langset` | Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. | `.langset de-DE ` or `.langset default` `.langsetdefault` `.langsetd` | Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. | `.langsetd en-US` or `.langsetd default` `.languageslist` `.langli` | List of languages for which translation (or part of it) exist atm. | `.langli` -`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logserver enable` or `.logserver disable` -`.logignore` | Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner Only** | `.logignore` -`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner Only** | `.logevents` -`.log` | Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner Only** | `.log userpresence` or `.log userbanned` -`.migratedata` | Migrate data from old bot configuration **Bot Owner Only** | `.migratedata` +`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot owner only** | `.logserver enable` or `.logserver disable` +`.logignore` | Toggles whether the `.logserver` command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot owner only** | `.logignore` +`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot owner only** | `.logevents` +`.log` | Toggles logging event. Disables it if it is active anywhere on the server. Enables if it isn't active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot owner only** | `.log userpresence` or `.log userbanned` +`.migratedata` | Migrate data from old bot configuration **Bot owner only** | `.migratedata` `.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced` -`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` +`.mute` | Mutes a mentioned user both from speaking and chatting. You can also specify time in minutes (up to 1440) for how long the user should be muted. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` or `.mute 30 @Someone` `.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone` `.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone` `.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone` `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` -`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner Only** | `.ropl` -`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **Bot Owner Only** | `.adpl` -`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner Only** | `.lipl` -`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner Only** | `.rmpl` +`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot owner only** | `.ropl` +`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **Bot owner only** | `.adpl` +`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot owner only** | `.lipl` +`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot owner only** | `.rmpl` `.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick` `.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban` `.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore` @@ -73,19 +73,19 @@ Command and aliases | Description | Usage `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` -`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner Only** | `.fwmsgs` -`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot Owner Only** | `.fwtoall` -`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot Owner Only** | `.connectshard 2` -`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot Owner Only** | `.leave 123123123331` -`.die` | Shuts the bot down. **Bot Owner Only** | `.die` -`.setname` `.newnm` | Gives the bot a new name. **Bot Owner Only** | `.newnm BotName` -`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner Only** | `.setstatus Idle` -`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only** | `.setav http://i.imgur.com/xTG3a1I.jpg` -`.setgame` | Sets the bots game. **Bot Owner Only** | `.setgame with snakes` -`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner Only** | `.setstream TWITCHLINK Hello` -`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot Owner Only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` -`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot Owner Only** | `.announce Useless spam` -`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner Only** | `.reloadimages` +`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs` +`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall` +`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2` +`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot owner only** | `.leave 123123123331` +`.die` | Shuts the bot down. **Bot owner only** | `.die` +`.setname` `.newnm` | Gives the bot a new name. **Bot owner only** | `.newnm BotName` +`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot owner only** | `.setstatus Idle` +`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot owner only** | `.setav http://i.imgur.com/xTG3a1I.jpg` +`.setgame` | Sets the bots game. **Bot owner only** | `.setgame with snakes` +`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot owner only** | `.setstream TWITCHLINK Hello` +`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot owner only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message` +`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot owner only** | `.announce Useless spam` +`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages` `.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30` `.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet` `.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.` @@ -94,13 +94,15 @@ Command and aliases | Description | Usage `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.vcrole` | Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.vcrole SomeRole` or `.vcrole` +`.vcrolelist` | Shows a list of currently set voice channel roles. | `.vcrolelist` `.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` `.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t` ###### [Back to ToC](#table-of-contents) ### ClashOfClans -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. **Requires ManageMessages server permission.** | `,cw 15 The Enemy Clan` `,startwar` `,sw` | Starts a war with a given number. | `,sw 15` @@ -115,31 +117,33 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### CustomReactions -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: | `.acr "hello" Hi there %user%` `.listcustreact` `.lcr` | Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. | `.lcr 1` or `.lcr all` `.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1` `.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1` `.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5` -`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner Only** | `.crstatsclear` or `.crstatsclear rng` +`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crad 44` +`.crad` | Toggles whether the message triggering the custom reaction will be automatically deleted. | `.crad 59` +`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot owner only** | `.crstatsclear` or `.crstatsclear rng` `.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3` ###### [Back to ToC](#table-of-contents) ### Gambling -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName` `$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy` `$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"` -`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner Only** | `$award 100 @person` or `$award 5 Role Of Gamblers` -`$take` | Takes a certain amount of currency from someone. **Bot Owner Only** | `$take 1 "@someguy"` +`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot owner only** | `$award 100 @person` or `$award 5 Role Of Gamblers` +`$take` | Takes a certain amount of currency from someone. **Bot owner only** | `$take 1 "@someguy"` `$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. | `$br 5` `$leaderboard` `$lb` | Displays the bot's currency leaderboard. | `$lb` `$race` | Starts a new animal race. | `$race` `$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5` -`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner Only** | `$startevent flowerreaction` +`$startevent` | Starts one of the events seen on public nadeko. **Bot owner only** | `$startevent flowerreaction` `$roll` | Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF` `$rolluo` | Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5` `$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15` @@ -147,10 +151,10 @@ Command and aliases | Description | Usage `$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh` `$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3` `$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t` -`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner Only** | `$slotstats` -`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner Only** | `$slottest 1000` +`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot owner only** | `$slotstats` +`$slottest` | Tests to see how much slots payout for X number of plays. **Bot owner only** | `$slottest 1000` `$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5` -`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama` +`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama` `$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot` `$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity` `$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus` @@ -159,7 +163,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Games -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more` `>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something` @@ -167,7 +171,7 @@ Command and aliases | Description | Usage `>rategirl` | Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. | `>rategirl @SomeGurl` `>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows` `>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello` -`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` +`>acrophobia` `>acro` | Starts an Acrophobia game. Second argument is optional round length in seconds. (default is 60) | `>acro` or `>acro 30` `>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot` `>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist` `>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies` @@ -180,9 +184,9 @@ Command and aliases | Description | Usage `>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend` `>typestart` | Starts a typing contest. | `>typestart` `>typestop` | Stops a typing contest on the current channel. | `>typestop` -`>typeadd` | Adds a new article to the typing contest. **Bot Owner Only** | `>typeadd wordswords` +`>typeadd` | Adds a new article to the typing contest. **Bot owner only** | `>typeadd wordswords` `>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3` -`>typedel` | Deletes a typing article given the ID. **Bot Owner Only** | `>typedel 3` +`>typedel` | Deletes a typing article given the ID. **Bot owner only** | `>typedel 3` `>tictactoe` `>ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | >ttt `>trivia` `>t` | Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint` `>tl` | Shows a current trivia leaderboard. | `>tl` @@ -191,19 +195,19 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Help -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `-modules` `-mdls` | Lists all bot modules. | `-modules` `-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name. | `-commands Administration` or `-cmds Admin` `-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h -cmds` or `-h` -`-hgit` | Generates the commandlist.md file. **Bot Owner Only** | `-hgit` +`-hgit` | Generates the commandlist.md file. **Bot owner only** | `-hgit` `-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide` `-donate` | Instructions for helping the project financially. | `-donate` ###### [Back to ToC](#table-of-contents) ### Music -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `!!next` `!!n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if !!rcs or !!rpl is enabled. | `!!n` or `!!n 5` `!!stop` `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s` @@ -219,9 +223,9 @@ Command and aliases | Description | Usage `!!shuffle` `!!sh` | Shuffles the current playlist. | `!!sh` `!!playlist` `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name` `!!soundcloudpl` `!!scpl` | Queue a Soundcloud playlist using a link. | `!!scpl soundcloudseturl` -`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner Only** | `!!lopl C:/music/classical` +`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot owner only** | `!!lopl C:/music/classical` `!!radio` `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: ) | `!!ra radio link here` -`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot Owner Only** | `!!lo C:/music/mysong.mp3` +`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot owner only** | `!!lo C:/music/mysong.mp3` `!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5` `!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3` `!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq` @@ -239,7 +243,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### NSFW -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri` `~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai` @@ -257,7 +261,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Permissions -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true` `;permrole` `;pr` | Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'. | `;pr role` @@ -276,9 +280,9 @@ Command and aliases | Description | Usage `;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole` `;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone` `;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]` -`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot Owner Only** | `;ubl add @SomeUser` or `;ubl rem 12312312313` -`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner Only** | `;cbl rem 12312312312` -`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot Owner Only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` +`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot owner only** | `;ubl add @SomeUser` or `;ubl rem 12312312313` +`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot owner only** | `;cbl rem 12312312312` +`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot owner only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer` `;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set it to 0 to remove the cooldown. | `;cmdcd "some cmd" 5` `;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds` `;srvrfilterinv` `;sfi` | Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner. | `;sfi` @@ -291,7 +295,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Pokemon -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy` `>movelist` `>ml` | Lists the moves you are able to use | `>ml` @@ -302,7 +306,7 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Searches -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- `~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU` `~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query` @@ -355,7 +359,7 @@ Command and aliases | Description | Usage `~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy` `~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer` `~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello` -`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner Only** | `~at` or `~at del` +`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot owner only** | `~at` or `~at del` `~autotranslang` `~atl` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. | `~atl en>fr` `~translangs` | Lists the valid languages for translation. | `~translangs` `~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest` @@ -363,12 +367,12 @@ Command and aliases | Description | Usage ###### [Back to ToC](#table-of-contents) ### Utility -Command and aliases | Description | Usage +Commands and aliases | Description | Usage ----------------|--------------|------- -`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot Owner Only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` +`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Requires ManageRoles server permission.** **Bot owner only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.togethertube` `.totube` | Creates a new room on and shows the link in the chat. | `.totube` `.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch` -`.inrole` | Lists every person from the provided role or roles, separated with space, on this server. You can use role IDs, role names (in quotes if it has multiple words), or role mention If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role` or `.inrole Role1 "Role 2" @role3` +`.inrole` | Lists every person from the specified role on this server. You can use role ID, role name. | `.inrole Some Role` `.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms` `.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"` `.channelid` `.cid` | Shows current channel ID. | `.cid` @@ -380,12 +384,14 @@ Command and aliases | Description | Usage `.shardid` | Shows which shard is a certain guild on, by guildid. | `.shardid 117523346618318850` `.stats` | Shows some basic stats for Nadeko. | `.stats` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` -`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner Only** | `.listservers 3` -`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.savechat 150` -`.activity` | Checks for spammers. **Bot Owner Only** | `.activity` +`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot owner only** | `.listservers 3` +`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot owner only** | `.savechat 150` +`.activity` | Checks for spammers. **Bot owner only** | `.activity` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calcops` | Shows all available operations in the `.calc` command | `.calcops` -`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner Only** | `.scsc` +`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows` +`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3` +`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot owner only** | `.scsc` `.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere` `.lcsc` | Leaves a cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` @@ -399,9 +405,9 @@ Command and aliases | Description | Usage `...` | Shows a random quote with a specified name. | `... abc` `.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` -`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` +`.deletequote` `.delq` | Deletes a quote with the specified ID. You have to be either server Administrator or the creator of the quote to delete it. | `.delq 123456` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.remind` | Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!` -`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot Owner Only** | `.remindtemplate %user%, do %message%!` +`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot owner only** | `.remindtemplate %user%, do %message%!` `.convertlist` | List of the convertible dimensions and currencies. | `.convertlist` `.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000` From 2d73f4bdfde4dd4adcd1d832928178eada46d260 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 03:51:54 +0200 Subject: [PATCH 08/26] .warn command, needs testing --- ...0170330000613_warning-commands.Designer.cs | 1346 +++++++++++++++++ .../20170330000613_warning-commands.cs | 78 + .../NadekoSqliteContextModelSnapshot.cs | 55 + .../Modules/Administration/Administration.cs | 95 -- .../Commands/LocalizationCommands.cs | 21 +- .../Commands/UserPunishCommands.cs | 358 +++++ .../Resources/CommandStrings.Designer.cs | 135 ++ src/NadekoBot/Resources/CommandStrings.resx | 45 + .../Resources/ResponseStrings.Designer.cs | 117 ++ src/NadekoBot/Resources/ResponseStrings.resx | 39 + .../Services/Database/IUnitOfWork.cs | 1 + .../Services/Database/Models/GuildConfig.cs | 10 +- .../Services/Database/Models/Warning.cs | 12 + .../Services/Database/NadekoContext.cs | 5 + .../Repositories/IWarningsRepository.cs | 11 + .../Impl/GuildConfigRepository.cs | 33 +- .../Repositories/Impl/WarningsRepository.cs | 37 + src/NadekoBot/Services/Database/UnitOfWork.cs | 3 + 18 files changed, 2293 insertions(+), 108 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170330000613_warning-commands.cs create mode 100644 src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs create mode 100644 src/NadekoBot/Services/Database/Models/Warning.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs create mode 100644 src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs diff --git a/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs b/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs new file mode 100644 index 00000000..28a99d1d --- /dev/null +++ b/src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs @@ -0,0 +1,1346 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170330000613_warning-commands")] + partial class warningcommands + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("DateAdded"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170330000613_warning-commands.cs b/src/NadekoBot/Migrations/20170330000613_warning-commands.cs new file mode 100644 index 00000000..5fb96271 --- /dev/null +++ b/src/NadekoBot/Migrations/20170330000613_warning-commands.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class warningcommands : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "WarningsInitialized", + table: "GuildConfigs", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateTable( + name: "Warnings", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + Forgiven = table.Column(nullable: false), + ForgivenBy = table.Column(nullable: true), + GuildId = table.Column(nullable: false), + Moderator = table.Column(nullable: true), + Reason = table.Column(nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Warnings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "WarningPunishment", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Count = table.Column(nullable: false), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + Punishment = table.Column(nullable: false), + Time = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_WarningPunishment", x => x.Id); + table.ForeignKey( + name: "FK_WarningPunishment_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_WarningPunishment_GuildConfigId", + table: "WarningPunishment", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Warnings"); + + migrationBuilder.DropTable( + name: "WarningPunishment"); + + migrationBuilder.DropColumn( + name: "WarningsInitialized", + table: "GuildConfigs"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 18195d44..97e9b393 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -559,6 +559,8 @@ namespace NadekoBot.Migrations b.Property("VoicePlusTextEnabled"); + b.Property("WarningsInitialized"); + b.HasKey("Id"); b.HasIndex("GuildId") @@ -1060,6 +1062,52 @@ namespace NadekoBot.Migrations b.ToTable("WaifuUpdates"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") @@ -1285,6 +1333,13 @@ namespace NadekoBot.Migrations .HasForeignKey("UserId") .OnDelete(DeleteBehavior.Cascade); }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); } } } diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 4eb9d28c..2f076ae3 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -218,101 +218,6 @@ namespace NadekoBot.Modules.Administration } } - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.BanMembers)] - [RequireBotPermission(GuildPermission.BanMembers)] - public async Task Ban(IGuildUser user, [Remainder] string msg = null) - { - if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); - } - catch - { - // ignored - } - } - - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("⛔️ " + GetText("banned_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.KickMembers)] - [RequireUserPermission(GuildPermission.ManageMessages)] - [RequireBotPermission(GuildPermission.BanMembers)] - public async Task Softban(IGuildUser user, [Remainder] string msg = null) - { - if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); - } - catch - { - // ignored - } - } - - await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); - try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } - - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle("☣ " + GetText("sb_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.KickMembers)] - [RequireBotPermission(GuildPermission.KickMembers)] - public async Task Kick(IGuildUser user, [Remainder] string msg = null) - { - if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) - { - await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); - return; - } - if (!string.IsNullOrWhiteSpace(msg)) - { - try - { - await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); - } - catch { } - } - - await user.KickAsync().ConfigureAwait(false); - await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() - .WithTitle(GetText("kicked_user")) - .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) - .ConfigureAwait(false); - } - [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.DeafenMembers)] diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index b61b2722..bc4a0952 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -16,25 +16,26 @@ namespace NadekoBot.Modules.Administration [Group] public class LocalizationCommands : NadekoSubmodule { + //Română, România private ImmutableDictionary supportedLocales { get; } = new Dictionary() { - {"zh-TW", "Chinese (Traditional), China" }, - {"zh-CN", "Chinese (Simplified), China"}, + {"zh-TW", "繁體中文, 台灣" }, + {"zh-CN", "简体中文, 中华人民共和国"}, {"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, - {"fr-FR", "French, France"}, + {"fr-FR", "Français, France"}, {"de-DE", "German, Germany"}, {"he-IL", "Hebrew, Israel" }, - {"it-IT", "Italian, Italy" }, + {"it-IT", "Italiano, Italia" }, //{"ja-JP", "Japanese, Japan"}, - {"ko-KR", "Korean, Korea" }, + {"ko-KR", "Korean, South Korea" }, {"nb-NO", "Norwegian (bokmål), Norway"}, - {"pl-PL", "Polish, Poland" }, - {"pt-BR", "Portuguese, Brazil"}, + {"pl-PL", "Polski, Polska" }, + {"pt-BR", "Português Brasileiro, Brasil"}, {"ru-RU", "Russian, Russia"}, - {"sr-Cyrl-RS", "Serbian, Serbia - Cyrillic"}, - {"es-ES", "Spanish, Spain"}, - {"sv-SE", "Swedish, Sweden"}, + {"sr-Cyrl-RS", "Српски, Србија"}, + {"es-ES", "Español, España"}, + {"sv-SE", "Svenska, Sverige"}, {"tr-TR", "Turkish, Turkey" } }.ToImmutableDictionary(); diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs new file mode 100644 index 00000000..0f54037f --- /dev/null +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -0,0 +1,358 @@ +using Discord; +using Discord.Commands; +using Discord.WebSocket; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Administration +{ + public partial class Administration + { + [Group] + public class UserPunishCommands : NadekoSubmodule + { + private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) + { + if (string.IsNullOrWhiteSpace(reason)) + reason = "-"; + + var guildId = guild.Id; + + var warn = new Warning() + { + UserId = userId, + GuildId = guildId, + Forgiven = false, + Reason = reason, + Moderator = modName, + }; + + int warnings; + List ps; + using (var uow = DbHandler.UnitOfWork()) + { + ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments)) + .WarnPunishments; + + uow.Warnings.Add(warn); + + warnings = uow.Warnings + .For(guildId, userId) + .Where(w => !w.Forgiven && w.UserId == userId) + .Count(); + + uow.Complete(); + } + + var p = ps.FirstOrDefault(x => x.Count == warnings); + + if (p != null) + { + var user = await guild.GetUserAsync(userId); + if (user == null) + return; + switch (p.Punishment) + { + case PunishmentAction.Mute: + await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)); + break; + case PunishmentAction.Kick: + await user.KickAsync().ConfigureAwait(false); + break; + case PunishmentAction.Ban: + await guild.AddBanAsync(user).ConfigureAwait(false); + break; + default: + break; + } + } + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task Warn(IGuildUser user, [Remainder] string reason = null) + { + try + { + await (await user.CreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor() + .WithDescription(GetText("warned_on", Context.Guild.ToString())) + .AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString())) + .AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-"))) + .ConfigureAwait(false); + } + catch { } + await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); + + await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(int page, IGuildUser user) + => Warnlog(page, user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(IGuildUser user) + => Warnlog(user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(int page, ulong userId) + => InternalWarnlog(userId, page - 1); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnlog(ulong userId) + => InternalWarnlog(userId, 0); + + private async Task InternalWarnlog(ulong userId, int page) + { + if (page < 0) + return; + Warning[] warnings; + using (var uow = DbHandler.UnitOfWork()) + { + warnings = uow.Warnings.For(Context.Guild.Id, userId); + } + + warnings = warnings.Skip(page * 9) + .Take(9) + .ToArray(); + + var embed = new EmbedBuilder().WithOkColor() + .WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())) + .WithFooter(efb => efb.WithText(GetText("page", page + 1))); + + if (!warnings.Any()) + { + embed.WithDescription(GetText("warnings_none")); + } + else + { + foreach (var w in warnings) + { + var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator); + if (w.Forgiven) + name = Format.Strikethrough(name) + GetText("warn_cleared_by", w.ForgivenBy); + + embed.AddField(x => x + .WithName(name) + .WithValue(w.Reason)); + } + } + + await Context.Channel.EmbedAsync(embed); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public Task Warnclear(IGuildUser user) + => Warnclear(user.Id); + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task Warnclear(ulong userId) + { + using (var uow = DbHandler.UnitOfWork()) + { + await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false); + uow.Complete(); + } + + await ReplyConfirmLocalized("warnings_cleared", + (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task WarnPunish(int number, PunishmentAction punish, int time = 0) + { + if (punish != PunishmentAction.Mute && time != 0) + return; + if (number <= 0) + return; + + using (var uow = DbHandler.UnitOfWork()) + { + var ps = uow.GuildConfigs.For(Context.Guild.Id).WarnPunishments; + var p = ps.FirstOrDefault(x => x.Count == number); + + if (p == null) + { + ps.Add(new WarningPunishment() + { + Count = number, + Punishment = punish, + Time = time, + }); + } + else + { + p.Count = number; + p.Punishment = punish; + p.Time = time; + uow._context.Update(p); + } + uow.Complete(); + } + + await ReplyConfirmLocalized("warn_punish_set", + Format.Bold(punish.ToString()), + Format.Bold(number.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + public async Task WarnPunish(int number) + { + if (number <= 0) + return; + + using (var uow = DbHandler.UnitOfWork()) + { + var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments; + var p = ps.FirstOrDefault(x => x.Count == number); + + if (p != null) + { + uow._context.Remove(p); + uow.Complete(); + } + } + + await ReplyConfirmLocalized("warn_punish_rem", + Format.Bold(number.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + public async Task WarnPunishList() + { + WarningPunishment[] ps; + using (var uow = DbHandler.UnitOfWork()) + { + ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments)) + .WarnPunishments + .OrderBy(x => x.Count) + .ToArray(); + } + + await Context.Channel.SendConfirmAsync( + GetText("warn_punish_list"), + string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"))).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Ban(IGuildUser user, [Remainder] string msg = null) + { + if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg)); + } + catch + { + // ignored + } + } + + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("⛔️ " + GetText("banned_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Softban(IGuildUser user, [Remainder] string msg = null) + { + if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg)); + } + catch + { + // ignored + } + } + + await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false); + try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle("☣ " + GetText("sb_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.KickMembers)] + [RequireBotPermission(GuildPermission.KickMembers)] + public async Task Kick(IGuildUser user, [Remainder] string msg = null) + { + if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()) + { + await ReplyErrorLocalized("hierarchy").ConfigureAwait(false); + return; + } + if (!string.IsNullOrWhiteSpace(msg)) + { + try + { + await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg)); + } + catch { } + } + + await user.KickAsync().ConfigureAwait(false); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("kicked_user")) + .AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true)) + .AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true))) + .ConfigureAwait(false); + } + } + } +} diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index cc7550b6..bba6abe1 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -9104,6 +9104,141 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to warn. + /// + public static string warn_cmd { + get { + return ResourceManager.GetString("warn_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warns a user.. + /// + public static string warn_desc { + get { + return ResourceManager.GetString("warn_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warn @b1nzy`. + /// + public static string warn_usage { + get { + return ResourceManager.GetString("warn_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnclear warnc. + /// + public static string warnclear_cmd { + get { + return ResourceManager.GetString("warnclear_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Clears all warnings from a certain user.. + /// + public static string warnclear_desc { + get { + return ResourceManager.GetString("warnclear_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnclear @PoorDude`. + /// + public static string warnclear_usage { + get { + return ResourceManager.GetString("warnclear_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnlog. + /// + public static string warnlog_cmd { + get { + return ResourceManager.GetString("warnlog_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to See a list of warnings of a certain user.. + /// + public static string warnlog_desc { + get { + return ResourceManager.GetString("warnlog_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnlog @b1nzy`. + /// + public static string warnlog_usage { + get { + return ResourceManager.GetString("warnlog_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnpunish warnp. + /// + public static string warnpunish_cmd { + get { + return ResourceManager.GetString("warnpunish_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sets a punishment for a certain number of warnings. Provide no punishment to remove.. + /// + public static string warnpunish_desc { + get { + return ResourceManager.GetString("warnpunish_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnpunish 5 Ban` or `{0}warnpunish 3`. + /// + public static string warnpunish_usage { + get { + return ResourceManager.GetString("warnpunish_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to warnpunishlist warnpl. + /// + public static string warnpunishlist_cmd { + get { + return ResourceManager.GetString("warnpunishlist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists punishments for warnings.. + /// + public static string warnpunishlist_desc { + get { + return ResourceManager.GetString("warnpunishlist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}warnpunishlist`. + /// + public static string warnpunishlist_usage { + get { + return ResourceManager.GetString("warnpunishlist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to weather we. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 790df4de..1f236f0a 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3222,4 +3222,49 @@ `{0}alias allin $bf 100 h` or `{0}alias "linux thingy" >loonix Spyware Windows` + + warnlog + + + See a list of warnings of a certain user. + + + `{0}warnlog @b1nzy` + + + warn + + + Warns a user. + + + `{0}warn @b1nzy` + + + warnclear warnc + + + Clears all warnings from a certain user. + + + `{0}warnclear @PoorDude` + + + warnpunishlist warnpl + + + Lists punishments for warnings. + + + `{0}warnpunishlist` + + + warnpunish warnp + + + Sets a punishment for a certain number of warnings. Provide no punishment to remove. + + + `{0}warnpunish 5 Ban` or `{0}warnpunish 3` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 1b0cd969..b440fe8a 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -736,6 +736,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Moderator. + /// + public static string administration_moderator { + get { + return ResourceManager.GetString("administration_moderator", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} moved from {1} to {2}. /// @@ -907,6 +916,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to page {0}. + /// + public static string administration_page { + get { + return ResourceManager.GetString("administration_page", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error. Most likely I don't have sufficient permissions.. /// @@ -1060,6 +1078,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Reason. + /// + public static string administration_reason { + get { + return ResourceManager.GetString("administration_reason", resourceCulture); + } + } + /// /// Looks up a localized string similar to Successfully removed role {0} from user {1}. /// @@ -1648,6 +1675,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been warned.. + /// + public static string administration_user_warned { + get { + return ResourceManager.GetString("administration_user_warned", resourceCulture); + } + } + /// /// Looks up a localized string similar to Username. /// @@ -1765,6 +1801,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to cleared by {0}. + /// + public static string administration_warn_cleared_by { + get { + return ResourceManager.GetString("administration_warn_cleared_by", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warning punishment list. + /// + public static string administration_warn_punish_list { + get { + return ResourceManager.GetString("administration_warn_punish_list", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Having {0} warnings will no longer trigger a punishment.. + /// + public static string administration_warn_punish_rem { + get { + return ResourceManager.GetString("administration_warn_punish_rem", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to I will apply {0} punishment to users with {1} warnings.. + /// + public static string administration_warn_punish_set { + get { + return ResourceManager.GetString("administration_warn_punish_set", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warned on {0} server. + /// + public static string administration_warned_on { + get { + return ResourceManager.GetString("administration_warned_on", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to On {0} at {1} by {2}. + /// + public static string administration_warned_on_by { + get { + return ResourceManager.GetString("administration_warned_on_by", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to All warnings have been cleared for {0}.. + /// + public static string administration_warnings_cleared { + get { + return ResourceManager.GetString("administration_warnings_cleared", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No warning on this page.. + /// + public static string administration_warnings_none { + get { + return ResourceManager.GetString("administration_warnings_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Warnlog for {0}. + /// + public static string administration_warnlog_for { + get { + return ResourceManager.GetString("administration_warnlog_for", resourceCulture); + } + } + /// /// Looks up a localized string similar to User {0} from text chat. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 6f8446b9..f8523242 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2278,4 +2278,43 @@ Owner ID: {2} Competitive playtime + + Moderator + + + page {0} + + + Reason + + + User {0} has been warned. + + + Warned on {0} server + + + On {0} at {1} by {2} + + + All warnings have been cleared for {0}. + + + No warning on this page. + + + Warnlog for {0} + + + cleared by {0} + + + Warning punishment list + + + Having {0} warnings will no longer trigger a punishment. + + + I will apply {0} punishment to users with {1} warnings. + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/IUnitOfWork.cs b/src/NadekoBot/Services/Database/IUnitOfWork.cs index c1c9479e..52cb01cf 100644 --- a/src/NadekoBot/Services/Database/IUnitOfWork.cs +++ b/src/NadekoBot/Services/Database/IUnitOfWork.cs @@ -23,6 +23,7 @@ namespace NadekoBot.Services.Database IPokeGameRepository PokeGame { get; } IWaifuRepository Waifus { get; } IDiscordUserRepository DiscordUsers { get; } + IWarningsRepository Warnings { get; } int Complete(); Task CompleteAsync(); diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 00693f16..4fe497c1 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using static NadekoBot.Modules.Administration.Administration; namespace NadekoBot.Services.Database.Models { @@ -72,10 +71,19 @@ namespace NadekoBot.Services.Database.Models public HashSet UnmuteTimers { get; set; } = new HashSet(); public HashSet VcRoleInfos { get; set; } public HashSet CommandAliases { get; set; } = new HashSet(); + public List WarnPunishments { get; set; } = new List(); + public bool WarningsInitialized { get; set; } //public List ProtectionIgnoredChannels { get; set; } = new List(); } + public class WarningPunishment : DbEntity + { + public int Count { get; set; } + public PunishmentAction Punishment { get; set; } + public int Time { get; set; } + } + public class CommandAlias : DbEntity { public string Trigger { get; set; } diff --git a/src/NadekoBot/Services/Database/Models/Warning.cs b/src/NadekoBot/Services/Database/Models/Warning.cs new file mode 100644 index 00000000..e5c8f4ff --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/Warning.cs @@ -0,0 +1,12 @@ +namespace NadekoBot.Services.Database.Models +{ + public class Warning : DbEntity + { + public ulong GuildId { get; set; } + public ulong UserId { get; set; } + public string Reason { get; set; } + public bool Forgiven { get; set; } + public string ForgivenBy { get; set; } + public string Moderator { get; set; } + } +} diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 4efb6150..a82cfde8 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -40,6 +40,7 @@ namespace NadekoBot.Services.Database public DbSet CurrencyTransactions { get; set; } public DbSet PokeGame { get; set; } public DbSet WaifuUpdates { get; set; } + public DbSet Warnings { get; set; } //logging public DbSet LogSettings { get; set; } @@ -272,6 +273,10 @@ namespace NadekoBot.Services.Database du.HasAlternateKey(w => w.UserId); #endregion + + #region Warnings + var warn = modelBuilder.Entity(); + #endregion } } } diff --git a/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs b/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs new file mode 100644 index 00000000..2b2e5ac4 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/IWarningsRepository.cs @@ -0,0 +1,11 @@ +using NadekoBot.Services.Database.Models; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories +{ + public interface IWarningsRepository : IRepository + { + Warning[] For(ulong guildId, ulong userId); + Task ForgiveAll(ulong guildId, ulong userId, string mod); + } +} diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 7098888d..01a44677 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -12,6 +12,18 @@ namespace NadekoBot.Services.Database.Repositories.Impl { } + private List DefaultWarnPunishments => + new List() { + new WarningPunishment() { + Count = 3, + Punishment = PunishmentAction.Kick + }, + new WarningPunishment() { + Count = 5, + Punishment = PunishmentAction.Ban + } + }; + public IEnumerable GetAllGuildConfigs() => _set.Include(gc => gc.LogSetting) .ThenInclude(ls => ls.IgnoredChannels) @@ -64,10 +76,19 @@ namespace NadekoBot.Services.Database.Repositories.Impl _set.Add((config = new GuildConfig { GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments, })); _context.SaveChanges(); } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } + return config; } @@ -82,10 +103,18 @@ namespace NadekoBot.Services.Database.Repositories.Impl _set.Add((config = new GuildConfig { GuildId = guildId, - Permissions = Permissionv2.GetDefaultPermlist + Permissions = Permissionv2.GetDefaultPermlist, + WarningsInitialized = true, + WarnPunishments = DefaultWarnPunishments, })); _context.SaveChanges(); } + + if (!config.WarningsInitialized) + { + config.WarningsInitialized = true; + config.WarnPunishments = DefaultWarnPunishments; + } return config; } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs new file mode 100644 index 00000000..4bf4c293 --- /dev/null +++ b/src/NadekoBot/Services/Database/Repositories/Impl/WarningsRepository.cs @@ -0,0 +1,37 @@ +using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; +using System; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Database.Repositories.Impl +{ + public class WarningsRepository : Repository, IWarningsRepository + { + public WarningsRepository(DbContext context) : base(context) + { + } + + public Warning[] For(ulong guildId, ulong userId) + { + var query = _set.Where(x => x.GuildId == guildId && x.UserId == userId) + .OrderByDescending(x => x.DateAdded); + + return query.ToArray(); + } + + public async Task ForgiveAll(ulong guildId, ulong userId, string mod) + { + await _set.Where(x => x.GuildId == guildId && x.UserId == userId) + .ForEachAsync(x => + { + if (x.Forgiven != true) + { + x.Forgiven = true; + x.ForgivenBy = mod; + } + }) + .ConfigureAwait(false); + } + } +} diff --git a/src/NadekoBot/Services/Database/UnitOfWork.cs b/src/NadekoBot/Services/Database/UnitOfWork.cs index 032c0bb7..02e78a97 100644 --- a/src/NadekoBot/Services/Database/UnitOfWork.cs +++ b/src/NadekoBot/Services/Database/UnitOfWork.cs @@ -54,6 +54,9 @@ namespace NadekoBot.Services.Database private IDiscordUserRepository _discordUsers; public IDiscordUserRepository DiscordUsers => _discordUsers ?? (_discordUsers = new DiscordUserRepository(_context)); + private IWarningsRepository _warnings; + public IWarningsRepository Warnings => _warnings ?? (_warnings = new WarningsRepository(_context)); + public UnitOfWork(NadekoContext context) { _context = context; From 111b4bc4654db1e5eb98f7a9670e0cabb116feb5 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 04:35:24 +0200 Subject: [PATCH 09/26] .unban added --- .../Commands/LocalizationCommands.cs | 4 +- .../Commands/UserPunishCommands.cs | 45 +++++++++++++++++++ .../Resources/CommandStrings.Designer.cs | 27 +++++++++++ src/NadekoBot/Resources/CommandStrings.resx | 9 ++++ .../Resources/ResponseStrings.Designer.cs | 18 ++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++ 6 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index bc4a0952..707d2af4 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -24,11 +24,11 @@ namespace NadekoBot.Modules.Administration {"nl-NL", "Dutch, Netherlands"}, {"en-US", "English, United States"}, {"fr-FR", "Français, France"}, - {"de-DE", "German, Germany"}, + {"de-DE", "Deutsch, Deutschland"}, {"he-IL", "Hebrew, Israel" }, {"it-IT", "Italiano, Italia" }, //{"ja-JP", "Japanese, Japan"}, - {"ko-KR", "Korean, South Korea" }, + {"ko-KR", "한국어, 대한민국" }, {"nb-NO", "Norwegian (bokmål), Norway"}, {"pl-PL", "Polski, Polska" }, {"pt-BR", "Português Brasileiro, Brasil"}, diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index 0f54037f..53479589 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -290,6 +290,51 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Unban([Remainder]string user) + { + var bans = await Context.Guild.GetBansAsync(); + + var bun = bans.FirstOrDefault(x => x.User.ToString().ToLowerInvariant() == user.ToLowerInvariant()); + + if (bun == null) + { + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); + return; + } + + await UnbanInternal(bun.User).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.BanMembers)] + [RequireBotPermission(GuildPermission.BanMembers)] + public async Task Unban(ulong userId) + { + var bans = await Context.Guild.GetBansAsync(); + + var bun = bans.FirstOrDefault(x => x.User.Id == userId); + + if (bun == null) + { + await ReplyErrorLocalized("user_not_found").ConfigureAwait(false); + return; + } + + await UnbanInternal(bun.User).ConfigureAwait(false); + } + + private async Task UnbanInternal(IUser user) + { + await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); + + await ReplyConfirmLocalized("unbanned_user", Format.Bold(user.ToString())).ConfigureAwait(false); + } + [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.KickMembers)] diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index bba6abe1..61163a92 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -8456,6 +8456,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to unban. + /// + public static string unban_cmd { + get { + return ResourceManager.GetString("unban_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unbans a user with the provided user#discrim or id.. + /// + public static string unban_desc { + get { + return ResourceManager.GetString("unban_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}unban kwoth#1234` or `{0}unban 123123123`. + /// + public static string unban_usage { + get { + return ResourceManager.GetString("unban_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to unclaim ucall uc. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 1f236f0a..db8b3f50 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3240,6 +3240,15 @@ `{0}warn @b1nzy` + + unban + + + Unbans a user with the provided user#discrim or id. + + + `{0}unban kwoth#1234` or `{0}unban 123123123` + warnclear warnc diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index b440fe8a..a8e6ed17 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1504,6 +1504,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been unbanned.. + /// + public static string administration_unbanned_user { + get { + return ResourceManager.GetString("administration_unbanned_user", resourceCulture); + } + } + /// /// Looks up a localized string similar to Undeafen successful.. /// @@ -1585,6 +1594,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User not found.. + /// + public static string administration_user_not_found { + get { + return ResourceManager.GetString("administration_user_not_found", resourceCulture); + } + } + /// /// Looks up a localized string similar to User's role added. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index f8523242..9ef50957 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2287,6 +2287,12 @@ Owner ID: {2} Reason + + User {0} has been unbanned. + + + User not found. + User {0} has been warned. From 090ad4f9811caa1d3c07bacb845905ad9d347b26 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 15:53:29 +0200 Subject: [PATCH 10/26] fixed tweezers in hangman, language names are no longer in english --- .../Administration/Commands/LocalizationCommands.cs | 13 +++++++------ .../Modules/Games/Commands/Hangman/HangmanGame.cs | 2 +- src/NadekoBot/data/{hangman.json => hangman2.json} | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) rename src/NadekoBot/data/{hangman.json => hangman2.json} (99%) diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 707d2af4..6930ad88 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -17,26 +17,27 @@ namespace NadekoBot.Modules.Administration public class LocalizationCommands : NadekoSubmodule { //Română, România + //Bahasa Indonesia, Indonesia private ImmutableDictionary supportedLocales { get; } = new Dictionary() { {"zh-TW", "繁體中文, 台灣" }, {"zh-CN", "简体中文, 中华人民共和国"}, - {"nl-NL", "Dutch, Netherlands"}, + {"nl-NL", "Nederlands, Nederland"}, {"en-US", "English, United States"}, {"fr-FR", "Français, France"}, {"de-DE", "Deutsch, Deutschland"}, - {"he-IL", "Hebrew, Israel" }, + {"he-IL", "עברית, ישראל"}, {"it-IT", "Italiano, Italia" }, - //{"ja-JP", "Japanese, Japan"}, + //{"ja-JP", "日本語, 日本"}, {"ko-KR", "한국어, 대한민국" }, - {"nb-NO", "Norwegian (bokmål), Norway"}, + {"nb-NO", "Norsk, Norge"}, {"pl-PL", "Polski, Polska" }, {"pt-BR", "Português Brasileiro, Brasil"}, - {"ru-RU", "Russian, Russia"}, + {"ru-RU", "Русский, Россия"}, {"sr-Cyrl-RS", "Српски, Србија"}, {"es-ES", "Español, España"}, {"sv-SE", "Svenska, Sverige"}, - {"tr-TR", "Turkish, Turkey" } + {"tr-TR", "Türkçe, Türkiye"} }.ToImmutableDictionary(); [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index b4b18e97..0f2f3bda 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Modules.Games.Hangman { public class HangmanTermPool { - const string termsPath = "data/hangman.json"; + const string termsPath = "data/hangman2.json"; public static IReadOnlyDictionary data { get; } static HangmanTermPool() { diff --git a/src/NadekoBot/data/hangman.json b/src/NadekoBot/data/hangman2.json similarity index 99% rename from src/NadekoBot/data/hangman.json rename to src/NadekoBot/data/hangman2.json index e13fd5ab..b93e6aa5 100644 --- a/src/NadekoBot/data/hangman.json +++ b/src/NadekoBot/data/hangman2.json @@ -3023,7 +3023,7 @@ "ImageUrl": "https://www.randomlists.com/img/things/tv.jpg" }, { - "Word": "twezzers", + "Word": "tweezers", "ImageUrl": "https://www.randomlists.com/img/things/twezzers.jpg" }, { From 324360073bfe00093323edb10d0305d75a14447f Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 16:00:27 +0200 Subject: [PATCH 11/26] spelling mistake --- src/NadekoBot/Modules/NadekoModule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index d71a2ba9..8b6788dd 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -69,7 +69,7 @@ namespace NadekoBot.Modules LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS."); text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!"; if (string.IsNullOrWhiteSpace(text)) - return "I can't tell you is the command executed, because there was an error printing out the response. Key '" + + return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this."; } return text; @@ -84,7 +84,7 @@ namespace NadekoBot.Modules } catch (FormatException) { - return "I cant tell if you command is executed, because there was an error printing out the response. Key '" + + return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" + lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this."; } } From 9cf03a1fb407cff41fc18917bbf9d73b8d4d4f52 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 30 Mar 2017 20:34:40 +0200 Subject: [PATCH 12/26] Finalized some things. closes #183 and #1059 --- .../Commands/UserPunishCommands.cs | 41 ++++++++++++++----- .../Resources/ResponseStrings.Designer.cs | 18 ++++++++ src/NadekoBot/Resources/ResponseStrings.resx | 6 +++ 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index 53479589..ded760c2 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration [Group] public class UserPunishCommands : NadekoSubmodule { - private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) + private async Task InternalWarn(IGuild guild, ulong userId, string modName, string reason) { if (string.IsNullOrWhiteSpace(reason)) reason = "-"; @@ -34,20 +34,20 @@ namespace NadekoBot.Modules.Administration Moderator = modName, }; - int warnings; + int warnings = 1; List ps; using (var uow = DbHandler.UnitOfWork()) { ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments)) .WarnPunishments; - - uow.Warnings.Add(warn); - warnings = uow.Warnings + warnings += uow.Warnings .For(guildId, userId) .Where(w => !w.Forgiven && w.UserId == userId) .Count(); + uow.Warnings.Add(warn); + uow.Complete(); } @@ -57,7 +57,7 @@ namespace NadekoBot.Modules.Administration { var user = await guild.GetUserAsync(userId); if (user == null) - return; + return null; switch (p.Punishment) { case PunishmentAction.Mute: @@ -72,7 +72,10 @@ namespace NadekoBot.Modules.Administration default: break; } + return p.Punishment; } + + return null; } [NadekoCommand, Usage, Description, Aliases] @@ -89,9 +92,16 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } catch { } - await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); + var punishment = await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false); - await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + if (punishment == null) + { + await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false); + } + else + { + await ReplyConfirmLocalized("user_warned_and_punished", Format.Bold(user.ToString()), Format.Bold(punishment.ToString())).ConfigureAwait(false); + } } [NadekoCommand, Usage, Description, Aliases] @@ -146,7 +156,7 @@ namespace NadekoBot.Modules.Administration { var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator); if (w.Forgiven) - name = Format.Strikethrough(name) + GetText("warn_cleared_by", w.ForgivenBy); + name = Format.Strikethrough(name) + " " + GetText("warn_cleared_by", w.ForgivenBy); embed.AddField(x => x .WithName(name) @@ -175,7 +185,7 @@ namespace NadekoBot.Modules.Administration } await ReplyConfirmLocalized("warnings_cleared", - (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()).ConfigureAwait(false); + Format.Bold((Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -254,9 +264,18 @@ namespace NadekoBot.Modules.Administration .ToArray(); } + string list; + if (ps.Any()) + { + list = string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}")); + } + else + { + list = GetText("warnpl_none"); + } await Context.Channel.SendConfirmAsync( GetText("warn_punish_list"), - string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"))).ConfigureAwait(false); + list).ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index a8e6ed17..34e12752 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1702,6 +1702,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to User {0} has been warned and {1} punishment has been applied.. + /// + public static string administration_user_warned_and_punished { + get { + return ResourceManager.GetString("administration_user_warned_and_punished", resourceCulture); + } + } + /// /// Looks up a localized string similar to Username. /// @@ -1900,6 +1909,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No punishments set.. + /// + public static string administration_warnpl_none { + get { + return ResourceManager.GetString("administration_warnpl_none", resourceCulture); + } + } + /// /// Looks up a localized string similar to User {0} from text chat. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 9ef50957..a94761da 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2296,6 +2296,9 @@ Owner ID: {2} User {0} has been warned. + + User {0} has been warned and {1} punishment has been applied. + Warned on {0} server @@ -2311,6 +2314,9 @@ Owner ID: {2} Warnlog for {0} + + No punishments set. + cleared by {0} From 3703e39cc917956f5528b6b57e0b245a15eea2c0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:01:33 +0200 Subject: [PATCH 13/26] -cmds now splits into multiple messages if too long --- src/NadekoBot/Modules/Help/Help.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index d6ceb1bd..4ca96023 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -55,8 +55,14 @@ namespace NadekoBot.Modules.Help await ReplyErrorLocalized("module_not_found").ConfigureAwait(false); return; } + var j = 0; + var groups = cmdsArray.GroupBy(x => j++ / 48).ToArray(); - await channel.SendTableAsync($"📃 **{GetText("list_of_commands")}**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false); + for (int i = 0; i < groups.Count(); i++) + { + await channel.SendTableAsync(i == 0 ? $"📃 **{GetText("list_of_commands")}**\n" : "", groups.ElementAt(i), el => $"{el.Aliases.First(),-15} {"[" + el.Aliases.Skip(1).FirstOrDefault() + "]",-8}").ConfigureAwait(false); + } + await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false); } From 272bf6b85e41f69d355433ca82d738361d800f38 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:03:22 +0200 Subject: [PATCH 14/26] Indonesian language completed --- .../Commands/LocalizationCommands.cs | 1 + .../Resources/ResponseStrings.id-ID.resx | 2285 +++++++++++++++++ .../ResponseStrings.sr-Cyrl-RS.Designer.cs | 260 -- 3 files changed, 2286 insertions(+), 260 deletions(-) create mode 100644 src/NadekoBot/Resources/ResponseStrings.id-ID.resx delete mode 100644 src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs diff --git a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs index 6930ad88..2eb70e4c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LocalizationCommands.cs @@ -27,6 +27,7 @@ namespace NadekoBot.Modules.Administration {"fr-FR", "Français, France"}, {"de-DE", "Deutsch, Deutschland"}, {"he-IL", "עברית, ישראל"}, + {"id-ID", "Bahasa Indonesia, Indonesia" }, {"it-IT", "Italiano, Italia" }, //{"ja-JP", "日本語, 日本"}, {"ko-KR", "한국어, 대한민국" }, diff --git a/src/NadekoBot/Resources/ResponseStrings.id-ID.resx b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx new file mode 100644 index 00000000..d2f4e2d2 --- /dev/null +++ b/src/NadekoBot/Resources/ResponseStrings.id-ID.resx @@ -0,0 +1,2285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Markas itu telah diklaim atau dihancurkan. + + + Markas itu telah dihancurkan. + + + Markas itu belum diklaim. + + + **DIHANCURKAN** markas #{0} di sebuah perang melawan {1} + + + {0} telah **MEMBATALKAN KLAIM** markas #{1} di sebuah perang melawan {2} + + + {0} Telah mengklaim sebuah markas #{1} di perang melawan {2} + + + @{0} Anda telah mengklaim markas #{1}. Anda tidak bisa mengklaim lagi. + + + Klaim dari @{0} di sebuah perang melawan {1} telah kadaluarsa. + + + Musuh + + + Info tentang perang melawan {0} + + + Jumlah markas yang salah. + + + Bukan ukuran perang yang benar. + + + Daftar perang aktif. + + + Tidak diklaim. + + + Anda tidak berpartisipasi di perang itu. + + + @{0} Antara anda tidak berpartisipasi di perang itu, atau markas itu telah dihancurkan. + + + Tidak ada perang aktif. + + + Ukuran + + + Perang melawan {0} telah dimulai. + + + Telah membuat perang melawan {0}. + + + Perang melawan {0} telah selesai. + + + Perang itu tidak ada. + + + Perang melawan {0} mulai! + + + Semua reaksi kustom telah dibersihkan. + + + Reaksi kustom telah dihapus. + + + Izin anda kurang. Dibutuhkan kepemilikan Bot untuk reaksi kostum global, dan Administrator untuk reaksi kustom server. + + + Daftar dari semua reaksi kustom. + + + Reaksi kustom. + + + Reaksi kustom baru + + + Tidak ada reaksi kustom yang ditemukan. + + + Tidak ada reaksi kustom ditemukan dengan id itu. + + + Tanggapan. + + + Status reaksi kustom + + + Status dibersihkan untuk reaksi kustom {0}. + + + Tidak ada data untuk aksi itu, aksi tidak dilakukan. + + + Aksi + + + Autohentai berhenti. + + + Tidak ada hasil yang ditemukan. + + + {0} sudah pingsan. + + + {0} sudah memiliki HP penuh. + + + Tipe anda sudah {0} + + + Digunakan {0}{1} di {2}{3} untuk {4} HP. + Kwoth used punch:type_icon: on Sanity:type_icon: for 50 damage. + + + Anda tidak bisa menyerang lagi tanpa serangan balik! + + + Anda tidak bisa menyerang diri sendiri. + + + {0} telah pingsan! + + + {0} disembuhkan dengan satu {1} + + + {0} memiliki {1} HP tersisa. + + + Anda tidak bisa menggunakan {0}. Ketik '{1}ml' untuk melihat daftar gerakan yang anda bisa gunakan. + + + Daftar gerakan untuk tipe {0} + + + Itu tidak efektif. + + + Anda tidak memiliki cukup {0} + + + {0} Dihidupkan dengan satu {1} + + + Anda menghidupkan diri sendiri dengan satu {0} + + + Tipe anda telah diganti ke {0} untuk sebuah {1} + + + Itu cukup efektif. + + + Itu sangatlah efektif! + + + Anda menggunakan terlalu banyak gerakan, jadi anda tidak bisa bergerak! + + + Tipe dari {0} adalah {1}. + + + Pengguna tidak ditemukan. + + + Anda pingsan, jadi anda tidak bisa bergerak! + + + **Penetapan role otomatis** ketika user bergabung sekarang telah **non aktif**. + + + **Penetapan role otomatis** ketika user bergabung sekarang telah **aktif**. + + + Lampiran + + + Avatar diubah. + + + Anda telah diban dari server {0}. +Alasan: {1} + + + 'banned' + PLURAL + + + Pengguna 'banned' + + + Nama bot diubah ke {0} + + + Status bot diubah ke {0}. + + + Penghapusan otomatis dari pesan 'bye' telah dimatikan. + + + Pesan 'bye' akan dihapus setelah {0} detik. + + + Pesan 'bye' sekarang: {0} + + + Nyalakan pesan 'bye' dengan menggunakan {0} + + + Pesan tinggal baru tersetel. + Fuzzy + + + Pengumuman tinggal dimatikan. + + + Pengumuman tinggal dinyalakan di channel ini. + + + Nama Channel telah diubah. + + + Nama lama. + + + Topik channel diubah. + + + Dibersihkan. + + + Konten + + + Berhasil membuat peran {0}. + + + Channel teks {0} telah dibuat. + + + Channel suara {0} telah dibuat. + + + Penulian berhasil. + + + Server {0} dihapus + + + Penghapusan otomatis telah diberhentikan karena invokasi pemerintah yang berhasil. + + + Sekarang akan secara otomatis menghapus invokasi perintah yang sukses. + + + Channel teks {0} dihapus. + + + Channel suara {0} dihapus. + + + Pesan dari + + + Berhasil menambahkan donatur baru. Jumlah donasi dari user ini: {0} 👑 + + + Terima kasih untuk orang yang terdaftar dibawah untuk menciptakan proyek ini! + + + Saya akan meneruskan DM kepada semua pemilik. + + + Saya akan meneruskan DM hanya ke pemilik pertama. + + + Saya akan meneruskan DM mulai dari sekarang. + + + Saya akan berhenti meneruskan DM mulai dari sekarang. + + + Penghapusan pesan sapaan otomatis telah dinonaktifkan. + + + Pesan pesan sapaan akan dihapus setelah {0} detik. + + + Pesan sapa DM sekarang: {0} + + + Aktifkan pesan sapa DM dengan mengetik {0} + + + Pesan sapa DM baru telah diset. + + + Pengumuman sapa DM dinonaktifkan. + + + Pengumuman sapa DM diaktifkan. + + + Pesan sapa sekarang: {0} + + + Aktifkan pesan sapa dengan mengetik {0} + + + Pesan sapa baru telah diset. + + + Pengumuman sapa dinonaktifkan. + + + Pengumuman sapa diaktifkan di channel ini. + + + Anda tidak bisa menggunakkan perintah ini pada pengguna dengan peran yang lebih tinggi atau setara dengan anda di dalam hierarki peran. + + + Gambar ditampilkan setelah {0} detik! + + + Format input tidak valid. + + + Parameter tidak valid. + + + {0} telah bergabung {1} + + + Anda telah dikeluarkan dari server (0}. +Alasan: {1} + + + Pengguna dikeluarkan + + + Daftar bahasa-bahasa + + + Bahasa server anda sekarang adalah {0} - {1} + + + Bahasa asli bot sekarang adalah {0} - {1} + + + Bahasa bot di set ke {0} - {1} + + + Gagal mengatur bahasa. Kunjungi bantuan untuk perintah ini. + + + Bahasa perintah ini sekarang di set ke {0} - {1} + + + {0} telah pergi {1} + + + Meninggalkan server {0} + + + Mencatat {0} event di channel ini. + + + Mencatat semua event di channel ini. + + + Pencatatan dinonaktifkan. + + + Event - event catatan yang anda dapat berlangganan: + + + Pencatatan akan mengabaikan {0} + + + Pencatatatn tidak akan mengabaikan {0} + + + Berhenti mencatat event {0}. + + + {0} telah menyebut peran - peran berikut + + + Pesan dari {0} `[Pemilik Bot]`: + + + Pesan terkirim. + + + {0} telah pindah dari {1} ke {2} + + + Pesan dihapus dalam #{0} + + + Pesan diperbarui dalam #{0} + + + Didiamkan. + PLURAL (users have been muted) + + + Didiamkan. + singular "User muted." + + + Kemungkinan besar saya tidak punya izin yang dibutuhkan untuk itu. + + + Peran diam baru telah diset + + + Saya butuh izin **Administrasi** untuk melakukan itu. + + + Pesan baru + + + Nama panggilan baru + + + Topik baru + + + Nama panggilan diubah + + + Tidak dapat menemukan server itu + + + Tidak ada potongan dengan ID itu ditemukan. + + + Pesan lama + + + Nama panggilan lama + + + Topik lama + + + Error. Kemungkinan besar saya tidak punya izin yang cukup. + + + Izin untuk server ini telah diatur ulang. + + + Perlindungan aktif + + + {0} telah **dinonaktifkan** pada server ini. + + + {0} diaktifkan + + + Error. Saya butuh izin ManageRoles + + + Tidak ada perlindungan diaktifkan. + + + Batas user harus diantara {0} dan {1}. + + + Jika {0} atau lebih user bergabung dalam {1} detik, Saya akan {2} mereka. + + + Waktu harus berada diantara {0} dan {1} detik. + + + Berhasil menghapus semua peran dari user {0} + + + Gagal menghapus peran. Saya tidak punya izin. + + + Warna dari peran {0} telah diubah. + + + Peran itu tidak ada. + + + Parameter yang ditentukan tidak valid. + + + Error disebabkan warna tidak valid atau tidak punya izin. + + + Berhasil menghapus peran {0} dari user {1} + + + Gagal menghapus peran. Saya tidak punya izin. + + + Nama peran diubah. + + + Gagal merubah nama peran. Saya tidak punya izin. + + + Anda tidak dapat mengedit peran yang lebih tinggi daripada peran tertinggi anda. + + + Pesan yang diputar: {0} telah dihapus + + + Peran {0} telah ditambahkan ke daftar. + + + {0} tidak ditemukan. Telah dibersihkan. + + + Peran {0} sudah ada di dalam daftar. + + + Ditambahkan. + + + Status bermain berotasi dinonaktifkan. + + + Status bermain berotasi diaktifkan + + + Ini adalah daftar status-status yang berotasi: +{0} + + + Tidak ada status bermain berotasi yang diset. + + + Anda sudah memiliki {0} peran. + + + Anda sudah memiliki {0} peran eksklusif yang ditetapkan sendiri. + + + Peran yang ditetapkan sendiri sekarang eksklusif! + + + Ada {0} peran yang ditetapkan sendiri + + + Peran itu tidak dapat ditetapkan sendiri. + + + Anda tidak memiliki {0} peran. + + + Peran yang ditetapkan sendiri sekarang tidak eksklusif! + + + Saya tidak dapat menambahkan peran itu pada anda. 'Saya tidak dapat menambahkan peran kepada pemilik atau peran lain yang lebih tinggi daripada peran saya di dalam hierarki peran.' + + + {0} telah dihapus dari daftar peran yang dapat ditetapkan sendiri. + + + Anda tidak lagi memiliki peran {0}. + + + Anda sekarang memiliki peran {0}. + + + Berhasil menambahkan peran {0} ke user {1} + + + Gagal menambahkan peran. Saya tidak punya izin. + + + Avatar baru telah diset! + + + Nama channel baru telah diset. + + + Permainan baru telah diset! + + + Aliran baru telah diset! + + + Topik channel baru telah diset! + + + Potongan {0} telah tersambung ulang. + + + Potongan {0} sedang menyambung ulang. + + + Mematikan + + + User tidak dapat mengirim lebih dari {0} pesan setiap {1} detik. + + + Mode lambat dimatikan. + + + Mode lambat dinyalakan. + + + Ban halus (Dikeluarkan) + PLURAL + + + {0} akan mengabaikan channel ini. + + + {0} tidak lagi akan mengabaikan channel ini. + + + Jika user memposting {0} pesan yang sama secara berurutan, Saya akan {1} mereka. + __IgnoredChannels__: {2} + + + Channel teks telah dibuat. + + + Channel teks telah dihancurkan. + + + penulian nonaktif. + + + Non-bisukan + singular + + + Nama pengguna + + + Nama pengguna telah diubah + + + Para pengguna + + + Pengguna dilarang + + + {0} telah **didiamkan** dari chatting. + + + {0} telah **tidak didiamkan** dari chatting. + + + User bergabung + + + User pergi + + + {0} telah **didiamkan** dari chat teks dan suara + + + Peran pengguna telah ditambahkan + + + Peran pengguna telah dihapuskan + + + {0} sekarang adalah {1} + + + {0} telah **tidak didiamkan** dari chat teks dan suara. + + + {0} telah bergabung di channel suara {1} . + + + {0} telah meninggalkan channel suara {1}. + + + {0} berpindah dari channel suara {1} ke {2}. + + + {0} telah **dibisukan** + + + {0} telah di **voice non-bisukan**. + + + Channel suara telah dibuat + + + Channel suara telah dihancurkan + + + Fitur suara + teks dinonaktifkan. + + + Fitur suara + teks diaktfikan. + + + Saya tidak memiliki izin **mengatur peran** dan/atau **mengatur channel**, jadi saya tidak dapat menjalankan 'suara+teks' di server {0}. + + + Anda mengaktifkan/menonaktifkan fitur ini dan **Saya tidak punya izin administrator**. Ini dapat menyebabkan beberapa isu, dan anda harus membersihkan sendiri channel-channel teks setelahnya. + + + Saya membutuhkan setidaknya izin **mengatur peran** dan **mengatur channel** untuk mengaktifkan fitur ini. (lebih memilih izin administrasi) + + + User {0} dari chat teks + + + User {0} dari chat teks dan suara + + + Pengguna {0} dari chat suara + + + Anda telah diban halus dari server {0}. +Alasan: {1} + + + Pengguna telah di unban + + + Migrasi selesai! + + + Error ketika migrasi, cek konsol bot untuk informasi lebih lanjut. + + + Pembaharuan kehadiran + + + Pengguna diban halus + + + Telah menyerahkan {0} ke {1} + + + Semoga lebih beruntung lain kali ^_^ + + + Selamat! Kamu memenangkan {0} karena hasil diatas {1} + + + Deck telah dikocok ulang. + + + Terlemparkan {0}. + User flipped tails. + + + Anda berhasil menebaknya! Anda memenangkan {0} + + + Angka tidak valid tertera. Anda dapat meleparkan 1 sampai {0} koin. + + + Tambahkan reaksi {0} pada pesan ini untuk mendapatkan {1}␣ + + + Event ini akan aktif selama {0} jam. + + + Event reaksi bunga telah dimulai! + + + Telah menghadiahi {0} ke {1} + X has gifted 15 flowers to Y + + + {0} memiliki {1} + X has Y flowers + + + Kepala + + + Leaderboard + + + Diserahkan {0} sampai {1} pengguna dari peran {2}. + + + Anda tidak bisa bertaruh lebih dari {0} + + + Anda tidak bisa bertaruh kurang dari {0} + + + Anda tidak memiliki cukup {0} + + + Tidak ada lagi kartu di dalam deck. + + + Pengguna yang diundi + + + Kamu mendapatkan {0}. + + + Bertaruh + + + WOAAHHHHHH!!! Selamat!!! x{0} + + + Sebuah {0}, x{1} + + + Wow! Beruntung! Three of a kind! x{0} + + + Good job! Dua {0} - bertaruh x{1} + + + Menang + + + User harus mengetikkan kode rahasia untuk mendapatkan {0}. +Berlangsung selama {1} detik. Jangan bilang bilang. Shhh. + + + Event SneakyGame berakhir. {0} pengguna telah menerima hadiah. + + + Event SneakyGameStatus telah dimulai + + + Ekor + + + berhasil mengambil {0} dari {1} + + + tidak dapat mengambil {0} dari{1} karena user itu tidak memiliki {2} sebanyak itu! + + + Kembali ke ToC + + + Hanya untuk pemilik bot + + + Memerlukan izin {0} channel. + + + Anda dapat mendukung project ini di patreon: <{0}> atau paypal: <{1}> + + + Daftar perintah dan alias + + + Daftar perintah telah dibuat ulang. + + + Ketik '{0}h CommandName' untuk melihat bantuan untuk perintah tersebut. Contoh '{0}h >8ball' + + + Saya tidak dapat menemukan perintah itu. Tolong verifikasi perintah itu ada sebelum mencoba lagi. + + + Deskripsi + + + Anda dapat mendukung projek NadekoBot di +Patreon <{0}> atau +Paypal <{1}> +Jangan lupa untuk meninggalkan nama atau ID Discord anda di dalam pesan. + +**Terima kasih**♥️ + + + **Daftar perintah**: <{0}> +**Panduan dan dokumentasi hosting dapat ditemukan disini**: <{1}> + + + Daftar perintah + + + Daftar modul + + + Ketik '{0}cmds ModuleName' untuk mendapatkan daftar perintah di dalam modul tersebut. Contoh '{0}cmds games' + + + Modul tersebut tidak ada. + + + Memerlukan izin {0} server. + + + Daftar isi + + + Penggunaan + + + Autohentai dimulai. Posting ulang setiap {0} detik dengan satu dari tanda berikut: +{1} + + + Tanda + + + Balap hewan + + + Gagal memulai karena tidak cukup peserta. + + + Balapan penuh!! Segera memulai. + + + {0} bergabung sebagai seekor {1} + + + {0} bergabung sebagai seekor {1} dan bertaruh {2}! + + + Ketik {0}jr untuk mengikuti balapan. + + + Dimulai dalam 20 detik atau ketika telah penuh. + + + Memulai dengan {0} peserta. + + + {0} sebagai {1} Memenangkan balapan! + + + {0} sebagai {1} Memenangkan balapan dan {2}! + + + Angka tidak valid. Anda dapat melemparkan {0}-{1} dadu bersamaan. + + + mendapatkan {0} + Someone rolled 35 + + + Dadu yang dilemparkan: {0} + Dice Rolled: 5 + + + Gagal memulai balapan. Balapan lain mungkin sedang berlangsung. + + + Tidak ada balapan di server ini + + + Angka kedua harus lebih besar daripada angka pertama. + + + Perubahan hati + + + Diklaim oleh + + + Perceraian + + + Suka + + + Harga + + + Tidak ada waifu yang belum diklaim. + + + Top Waifu + + + Afinitas anda sudah ditetapkan ke waifu tersebut atau anda sedang mencoba menghilangkan afinitas tanpa mempunyainya. + + + Mengubah afinitas mereka dari {0} ke {1} + +*Ini dapat ditanyakan moralitasnya.* 🤔 + Make sure to get the formatting right, and leave the thinking emoji + + + Anda harus menunggu {0} jam dan {1} menit untuk mengubah afinitas anda lagi. + + + Afinitas anda telah diulang. Anda tidak lagi memiliki seseorang yang anda sukai. + + + ingin menjadi waifu si {0}. Aww <3 + + + mengklaim {0} sebagai waifu dia seharga {1}! + + + Kamu telah menceraikan waifu yang menyukaimu. Kamu monster tanpa hati. +{0} menerima {1} sebagai kompensasi. + + + Anda tidak bisa merubah afinitas ke diri sendiri, anda egois. + + + 🎉 Cinta mereka dipenuhi! 🎉 +Nilai {0} sekarang adalah {1}! + + + Tidak ada waifu semurah itu. Anda harus membayar setidaknya {0} untuk mendapatkan waifu, meskipun harga mereka lebih rendah. + + + Anda harus membayar {0} atau lebih untuk mengklaim waifu tersebut! + + + Waifu itu bukan milikmu. + + + Anda tidak bisa mengklaim diri sendiri. + + + Anda baru saja bercerai. Anda harus menunggu {0} jam dan {1} menit untuk bercerai lagi. + + + Tidak seorangpun + + + Anda telah menceraikan waifu yang tidak menyukaimu. Anda menerima {0} kembali. + + + 8ball + + + Acrophobia + + + Permainan selesai tanpa pengajuan. + + + Tidak ada pilihan dikirim. Permainan selesai tanpa adanya pemenang. + + + Akronim adalah {0}. + + + Permainan Acrophobia sudah berlangsung di channel ini. + + + Permainan dimulai. Buat sebuah kalimat dengan akronim berikut: {0}. + + + Anda memiliki {0} detik untuk mengirimkan pengajuan. + + + {0} mengirim kalimat mereka. (total {1}) + + + Pilih dengan mengetik nomor dari pengajuan. + + + {0} mengirimkan pilihan mereka! + + + Pemenangnya adalah {0} dengan {1} poin. + + + {0} adalah pemenang karena merupakan satu-satunya pengguna yang mengajukan submisi! + + + Pertanyaan + + + Sebuah seri! Keduanya memilih {0} + + + {0} menang! {1} mengalahkan {2} + + + Waktu pengajuan selesai. + + + Animal Race telah berlangsung. + + + Total: {0} Rata - rata: {0} + + + Kategori + + + Cleverbot dinonaktifkan di server ini. + + + Cleverbot diaktifkan di server ini + + + Pembuatan mata uang telah dinonaktifkan di channel ini. + + + Pembuatan mata uang telah diaktifkan di channel ini. + + + {0} acak {1} telah muncul! + plural + + + Sebuah {0} muncul! + + + Gagal memuat pertanyaan + + + Permainan dimulai + + + Permainan Hangman dimulai + + + Permainan Hangman telah berlangsung di channel ini + + + Ada kesalahan saat memulai Hangman + Fuzzy + + + Daftar dari "{0}hangman" tipe istilah: + + + Leaderboard + + + Anda tidak punya cukup {0} + + + Tidak ada hasil + + + memilih {0} + Kwoth picked 5* + + + {0} menanam {1} + Kwoth planted 5* + + + Permainan trivia sedang berlangsung di server ini. + + + Permainan Trivia + + + {0} menebaknya! Jawabannya adalah: {1} + + + Tidak ada trivia yang sedang berlangsung di server ini. + + + {0} memiliki {1} poin + + + Berhenti setelah pertanyaan ini. + + + Waktu habis! Jawaban yang benar adalah {0} + + + {0} berhasil menebaknya dan memenangkan permainan! Jawabannya adalah: {1} + + + Anda tidak bisa bermain melawan diri sendiri. + + + Permainan TicTacToe sedang berlangsung di channel ini. + + + Sebuah seri! + + + telah membuat permainan TicTacToe. + + + {0} telah menang! + + + Mendapat tiga. + Fuzzy + + + TIdak ada jalan tersisa! + + + Waktu habis! + + + Giliran {0} + + + {0} vs {1} + + + Mencoba untuk mengantri {0} lagu... + + + Autoplay dimatikan. + + + Autoplay diaktifkan. + + + Volume awal di set ke {0}% + + + Antrian direktori selesai. + + + fairplay + + + Lagu selesai + + + Fair play dimatikan. + + + Fair play diaktifkan. + + + Dari posisi + + + id + + + Input tidak valid. + + + Sekarang, waktu bermain maksimal tidak memiliki batas. + + + Batas waktu bermain di set ke {0} detik. + + + Antrian maks untuk musik di set ke tidak terbatas. + + + Antrian maks untuk musik di set ke {0} lagu. + + + Anda harus berada di dalam channel suara di server ini. + + + Nama + + + Sekarang memutar + + + Tidak ada pemutar musik yang aktif. + + + Tidak ada hasil pencarian. + + + Pemutaran musik berhenti sebentar. + + + Antrian pemutar musik - Halaman {0}/{1} + + + Memutar lagu + + + `#{0}` - **{1}** oleh *{2}* ({3} lagu) + + + Halaman {1} playlist yang tersimpan + + + Playlist dihapus + + + Gagal untuk menghapus playlist. Playlist tidak ditemukan, atau anda bukan pemilik playlist tersebut. + + + Playlist dengan ID tersebut tidak ditemukan. + + + Antrian playlist selesai. + + + Playlist disimpan + + + Batasan milik {0} + + + Antrian + + + Antrian lagu + + + Antrian lagu dibersihkan + + + Antrian penuh pada {0}/{0}. + + + Menghapus lagu + context: "removed song #5" + + + Mengulang lagu yang diputar saat ini + + + Mengulang playlist + + + Musik diulang + + + Pengulangan musik diberhentikan. + + + Pemutaran kembali lagu dilanjutkan. + + + Pengulangan playlist dibatalkan. + + + Pengulangan playlist diaktifkan + + + Sekarang saya akan mengeluarkan lagu yang sedang diputar, yang telah diputar, yang dihentikan dan menghapus lagu-lagu di channel ini. + + + Lewat ke `{0}:{1}` + + + Lagu diacak + + + Lagu dipindahkan + + + {0}jam {1}menit {2}detik + + + Pada posisi + + + tidak terbatas + + + Volume harus di antara 0 dan 100 + + + Volume diset pada {0}% + + + Menonaktifkan pemakaian dari SEMUA MODUL pada channel {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL pada channel {0}. + + + Diizinkan + + + Menonaktifkan pemakaian dari SEMUA MODUL untuk peran {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL untuk peran {0}. + + + Menonaktifkan pemakaian dari SEMUA MODUL di server ini. + + + Mengaktifkan pemakaian dari SEMUA MODUL di server ini. + + + Menonaktifkan pemakaian dari SEMUA MODUL untuk pengguna {0}. + + + Mengaktifkan pemakaian dari SEMUA MODUL untuk pengguna {0}. + + + Mendaftarhitamkan {0} dengan ID {1} + + + Perintah {0} sekarang memiliki jeda selama {1} detik. + + + Perintah {0} sekarang tidak memiliki jeda dan semua jeda yang ada telah dibersihkan. + + + Tidak ada perintah jeda yang ditentukan. + + + Harga perintah + + + Menonaktifkan pemakaian pada {0} {1} pada channel {2}. + + + Mengaktifkan pemakaian pada {0} {1} pada channel {2}. + + + Ditolak + + + Menambahkan kata {0} pada daftar saringan kata. + + + Daftar saringan kata-kata + + + Mencabut kata {0} dari daftar saringan kata-kata. + + + Parameter kedua salah (Harus nomor diantara {0} dan {1}) + + + Penyaringan undangan dinonaktifkan di channel ini. + + + Penyaringan undangan diaktifkan di server ini. + + + Penyaringan undangan dinonaktifkan di server ini. + + + Penyaringan undangan diaktifkan di server ini. + + + Memindakan izin {0} dari #{1} kepada #{2} + + + Tidak dapat menemukan izin pada indeks #{0} + + + Tidak ada biaya di set. + + + perintah + Gen (of command) + + + modul + Gen. (of module) + + + Halaman perizinan {0} + + + Peran izin sekarang adalah {0} + + + Pengguna memerlukan {0} peran untuk dapat merubah izin. + + + Izin tidak ditemukan dalam indeks tersebut. + + + Mencabut izin #{0} - {1} + + + Menonaktifkan pemakaian pada {0} {1} untuk peran {2}. + + + Mengaktifkan pemakaian pada {0} {1} untuk peran {2}. + + + sec. + Short of seconds. + + + Menonaktifkan pemakaian dari {0} {1} pada server ini. + + + Mengaktifkan pemakaian dari {0} {1} pada server ini. + + + Menghapus {0} dengan ID {1} dari daftar hitam + + + tidak dapat diganti + + + Menonaktifkan pemakaian dari {0} {1} untuk {2} pengguna. + + + Mengaktifkan pemakaian dari {0} {1} untuk {2} pengguna. + + + Saya tidak akan lagi memperlihatkan izin peringatan. + + + Sekarang saya akan memperlihatkan izin peringatan. + + + Penyaringan kata pada channel ini dinonaktifkan. + + + Penyaringan kata pada channel ini diaktifkan. + + + Penyaringan kata pada server ini dinonaktifkan. + + + Penyaringan kata pada server ini diaktifkan. + + + Kemampuan + + + Belum ada anime favorit + + + Memulai terjemahan otomatis dari pesan di channel ini. Pesan pengguna akan otomatis dihapus. + + + Terjemahan bahasa otomatis anda telah dicabut. + + + Terjemahan bahasa otomatis anda telah diset pada {0}>{1} + + + Memulai terjemahan otomatis dari pesan-pesan di channel ini. + + + Menghentikan terjemahan otomatis dari pesan-pesan di channel ini. + + + Format input buruk, atau terjadi kesalahan. + + + Tidak dapat menemukan kartu tersebut. + + + fakta + + + Bab + + + Komik # + + + Kekalahan kompetitif + + + Kompetitif yang dimainkan + + + Tingkat kompetitif + + + Kemenangan kompetitif + + + Selesai + + + Kondisi + + + Biaya + + + Tanggal + + + Jelaskan: + + + Terjatuh. + + + Episode + + + Kesalahan terjadi. + + + Contoh + + + Gagal menemukan animu tersebut + + + Gagal menemukan mango tersebut + + + Aliran + + + Gagal menemukan definisi dari label tersebut. + + + Tinggi/Berat + + + {0}m/{1}kg + + + Kelembaban + + + Pencarian gambar untuk: + + + Gagal untuk menemukan film tersebut. + + + Kesalahan sumber atau target bahasa. + + + Candaan tidak dimuat. + + + Lintang/Bujur + + + Tingkat + + + Daftar dari {0}tempat yang ditandai + Don't translate {0}place + + + Lokasi + + + Barang barang sihir tidak dimuat. + + + Profil MAL {0} + + + Pemilik Bot tidak menentukan MashapeApiKey. Anda tidak dapat menggunakan fungsi ini. + + + Min/Maks + + + Channel tidak ditemukan. + + + Hasil tidak ditemukan. + + + Tertahan + + + url asli + + + Sebuah osu! API key diperlukan. + + + Gagal mengambil tanda osu! + + + Ditemukan diantara {0} gambar. Memperlihatkan acak {0}. + + + Pengguna tidak ditemukan! Silahkan cek daerah dan BattleTag sebelum mencoba lagi. + + + Rencana untuk menonton + + + Peron + + + Kemampuan tidak ditemukan. + + + Pokemon tidak ditemukan. + + + Tautan profil: + + + Kualitas + + + Waktu bermain cepat + + + Kemenangan cepat + + + Penilaian + + + Skor: + + + Pencarian untuk: + + + Gagal untuk mempersingkat url tersebut. + + + Url pendek + + + Ada sesuatu yang salah. + + + Harap menentukan parameter pencarian. + + + Status + + + Menyimpan url + + + Streamer {0} sedang offline. + + + Streamer {0} online dengan {1} penonton. + + + Anda mengikuti {0} stream di server ini. + + + Anda tidak mengikuti stream di server ini. + + + Stream tidak ditemukan. + + + Stream mungkin tidak ada. + + + Menghilangkan {0} stream ({1}) dari notifikasi. + + + Saya akan memberitahu channel ini saat status berubah. + + + Matahari terbit + + + Matahari terbenam + + + Temperatur + + + Judul: + + + Top 3 favorit anime: + + + Terjemahan: + + + Tipe + + + Gagal menemukan definisi untuk istilah tersebut + + + Url + + + Penonton + + + Menonton + + + Gagal menemukan istilah tersebut dalam wikia yang ditentukan. + + + Harap memasukkan target wikia, diikuti dengan pertanyaan pencarian. + + + Halaman tidak ditemukan. + + + Kecepatan angin + + + {0} champion paling sering di ban + + + Gagal menyodifikasi kalimat anda. + + + Bergabung + + + `{0}.` {1} [{2:F2}/s] - {3} total + /s and total need to be localized to fit the context - +`1.` + + + Halaman aktifitas #{0} + + + {0} total pengguna. + + + Penulis + + + ID Bot + + + Daftar fungsi di perintah {0)calc + + + {0} dari channel ini adalah {1} + + + Topik channel + + + Perintah dijalankan + + + {0} {1} sama dengan {2} {3} + + + Satuan yang dapat digunakan oleh converter + + + Tidak bisa mengubah {0} menjadi {1}: satuan tidak ditemukan + + + Tidak dapat mengubah {0} ke {1}: tipe untuk tidak sama + + + Dibuat di + + + Mengikuti saluran silang server. + + + Saluran silang server ditinggalkan. + + + Ini adalah token CSC anda + + + emoji kustom + + + Kesalahan + + + Ciri - ciri + + + ID + + + Indeks di luar jarak. + + + Daftar pengguna pada peran {0} + + + Anda tidak diizinkan untuk menggunakan perintah ini pada peran dengan banyak pengguna di dalamnya untuk mencegah penyalahgunaan. + + + Nilai {0} salah. + Invalid months value/ Invalid hours value + + + Bergabung Discord + + + Bergabung server + + + ID: {0} +Anggota: {1} +ID Pemilik: {2} + + + Server tidak ditemukan di halaman tersebut. + + + Daftar dari pengulangan + + + Anggota + + + Memori + + + Pesan + + + Pengulang pesan + + + Nama + + + Nama panggilan + + + Tidak seorangpun memainkan game tersebut + + + Tidak ada pengulangan aktif. + + + Tidak ada peran di halaman ini. + + + Tidak ada pecahan di halaman ini. + + + Tidak ada topik yang ditentukan + + + Pemilik + + + IDs pemilik + + + Kehadiran + + + {0} Servers +{1} Channel Teks +{2} Channel Suara + + + Menghapus semua kutipan dengan {0} kata kunci. + + + Halaman {0} dari kutipan + + + Tidak ada kutipan pada halaman ini. + + + Tidak ditemukan kutipan yang dapat anda hapus. + + + Kutipan ditambahkan + + + Kutipan #{0} dihapus. + + + Wilayah + + + Terdaftar pada + + + Saya akan mengigatakn {0} untuk {1} dalam {2} '({3:d:M.yyyy.} saat {4:HH:mm} + + + Bukan format waktu yang benar. Silakan periksa daftar perintah. + + + Template mengingatkan baru disetel. + + + Mengulang {0} setiap {1} hari, {2} jam dan {3} menit. + + + Daftar pemutaran. + + + Tidak ada pemutaran di server ini. + + + #{0} berhenti. + + + Tidak ada pesan mengulang ditemukan di server ini. + + + Hasil + + + Peran + + + Halaman #{0} dari semua peran di server ini: + + + Halaman #{0} dari peran untuk {1} + + + Tidak ada warna di format benar. Gunakan '#00ff00' sebagai contoh. + + + Memulai pemutaran di peran {0}. + + + Memberhentikan warna memutar untuk peran {0} + + + {0} pada server ini adalah {1} + + + Info server + + + Pecahan + + + Statistik pecahan + + + Pecahan **#{0}** sedang di dalam keadaan {1} di {2} server. + + + **Nama:** {0} **Tautan:** {1} + + + Emojis khusus tidak ditemukan. + + + Memainkan {0} lagu, {1} menunggu + + + Channel teks + + + Ini adalah tautan untuk ruangan anda: + + + Uptime + + + {0} dari pengguna {1} adalah {2} + Id of the user kwoth#1234 is 123123123123 + + + Pengguna + + + Channel suara + + + Anda telah bergabung pada perlombaan ini! + + + Hasil pemilihan saat ini + + + Tidak ada suara terkirim. + + + Pemilihan telah dimulai di server ini. + + + 📃 {0} telah membuat pemilihan yang memerlukan perhatian anda: + + + '{0}.' {1} dengan {2} suara. + + + {0} memilih. + Kwoth voted. + + + Kirim saya pesan pribadi dengan angka yang sesuai dari jawaban. + + + Kirim pesan dengan menggunakan nomor dari jawaban. + + + Terima kasih telah memilih, {0} + + + {0} total suara dikirim. + + + Mengambil barang tersebut dengan mengetik `{0}ambil` + + + Ambil dengan mengetik '{0}pick' + + + Pengguna tidak ditemukan. + + + halaman {0} + + + Anda harus berada pada channel suara di server ini. + + + Tidak ada peran untuk saluran suara. + + + {0} telah **dibisukan** dari teks dan saluran suara selama {1} menit. + + + Pengguna yang bergabung {0} channel suara akan mendapatkan peran {1}. + + + Pengguna yang bergabung {0} channel suara tidak lagi mendapatkan peran. + + + Peran channel suara + + + Mereaksi reaksi kustom menggunakan pesan dengan id {0} tidak akan dihapus secara otomatis. + + + Mereaksikan reaksi kustom menggunakan pesan dengan id {0} akan dihapus secara otomatis. + + + Pesan respon untuk reaksi kustom dengan id {0} tidak akan dikirim sebagai DM. + + + Pesan respon untuk reaksi kustom dengan id {0} akan dikirim sebagai DM. + + + Alias tidak ditemukan + + + Mengetik {0} sekarang akan menjadi alias dari {1}. + + + Daftar alias + + + Perintah {0} sekarang tidak memiliki alias. + + + Perintah {0} tidak mempunyai alias. + + + Waktu bermain kompetitif + + + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs deleted file mode 100644 index 4d43d571..00000000 --- a/src/NadekoBot/Resources/ResponseStrings.sr-Cyrl-RS.Designer.cs +++ /dev/null @@ -1,260 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace NadekoBot.Resources { - using System; - using System.Reflection; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class ResponseStrings_sr_SP { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - internal ResponseStrings_sr_SP() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NadekoBot.Resources.ResponseStrings-sr-SP", typeof(ResponseStrings_sr_SP).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to {0} has already fainted.. - /// - public static string pokemon_already_fainted { - get { - return ResourceManager.GetString("pokemon_already_fainted", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} already has full HP.. - /// - public static string pokemon_already_full { - get { - return ResourceManager.GetString("pokemon_already_full", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your type is already {0}. - /// - public static string pokemon_already_that_type { - get { - return ResourceManager.GetString("pokemon_already_that_type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to used {0}{1} on {2}{3} for {4} damage.. - /// - public static string pokemon_attack { - get { - return ResourceManager.GetString("pokemon_attack", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't attack again without retaliation!. - /// - public static string pokemon_cant_attack_again { - get { - return ResourceManager.GetString("pokemon_cant_attack_again", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't attack yourself.. - /// - public static string pokemon_cant_attack_yourself { - get { - return ResourceManager.GetString("pokemon_cant_attack_yourself", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} has fainted!. - /// - public static string pokemon_fainted { - get { - return ResourceManager.GetString("pokemon_fainted", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to healed {0} with one {1}. - /// - public static string pokemon_healed { - get { - return ResourceManager.GetString("pokemon_healed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} has {1} HP remaining.. - /// - public static string pokemon_hp_remaining { - get { - return ResourceManager.GetString("pokemon_hp_remaining", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You can't use {0}. Type `{1}ml` to see a list of moves you can use.. - /// - public static string pokemon_invalid_move { - get { - return ResourceManager.GetString("pokemon_invalid_move", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Movelist for {0} type. - /// - public static string pokemon_moves { - get { - return ResourceManager.GetString("pokemon_moves", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You don't have enough {0}. - /// - public static string pokemon_no_currency { - get { - return ResourceManager.GetString("pokemon_no_currency", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's not effective.. - /// - public static string pokemon_not_effective { - get { - return ResourceManager.GetString("pokemon_not_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to revived {0} with one {1}. - /// - public static string pokemon_revive_other { - get { - return ResourceManager.GetString("pokemon_revive_other", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You revived yourself with one {0}. - /// - public static string pokemon_revive_yourself { - get { - return ResourceManager.GetString("pokemon_revive_yourself", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your type has been changed to {0} for a {1}. - /// - public static string pokemon_settype_success { - get { - return ResourceManager.GetString("pokemon_settype_success", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's somewhat effective.. - /// - public static string pokemon_somewhat_effective { - get { - return ResourceManager.GetString("pokemon_somewhat_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to It's super effective!. - /// - public static string pokemon_super_effective { - get { - return ResourceManager.GetString("pokemon_super_effective", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You used too many moves in a row, so you can't move!. - /// - public static string pokemon_too_many_moves { - get { - return ResourceManager.GetString("pokemon_too_many_moves", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type of {0} is {1}. - /// - public static string pokemon_type_of_user { - get { - return ResourceManager.GetString("pokemon_type_of_user", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User not found.. - /// - public static string pokemon_user_not_found { - get { - return ResourceManager.GetString("pokemon_user_not_found", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You fainted, so you are not able to move!. - /// - public static string pokemon_you_fainted { - get { - return ResourceManager.GetString("pokemon_you_fainted", resourceCulture); - } - } - } -} From 0a7bbd60f77870e8f3e41334a4a19e1a4f14adf0 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Fri, 31 Mar 2017 14:07:18 +0200 Subject: [PATCH 15/26] Startup commands added. Closes #195; .sclist .scadd .scrm .scclr. Won't support music commands atm, but that can come in the future, there is support for it (your current voice channel is recorded when adding) --- .../Attributes/OwnerOnlyAttribute.cs | 2 +- ...0170331093025_startup-commands.Designer.cs | 1385 +++++++++++++++++ .../20170331093025_startup-commands.cs | 51 + .../NadekoSqliteContextModelSnapshot.cs | 39 + .../Modules/Administration/Administration.cs | 2 +- .../Administration/Commands/SelfCommands.cs | 168 +- .../Commands/UserPunishCommands.cs | 5 +- .../CustomReactions/CustomReactions.cs | 2 +- .../Games/Commands/CleverBotCommands.cs | 2 +- .../Resources/CommandStrings.Designer.cs | 135 ++ src/NadekoBot/Resources/CommandStrings.resx | 45 + .../Resources/ResponseStrings.Designer.cs | 72 + src/NadekoBot/Resources/ResponseStrings.resx | 24 + src/NadekoBot/Services/CommandHandler.cs | 274 ++-- .../Services/Database/Models/BotConfig.cs | 13 + .../Repositories/IBotConfigRepository.cs | 7 +- .../Repositories/Impl/BotConfigRepository.cs | 11 +- 17 files changed, 2090 insertions(+), 147 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170331093025_startup-commands.cs diff --git a/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs b/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs index 410a24af..eefc489c 100644 --- a/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs +++ b/src/NadekoBot/Attributes/OwnerOnlyAttribute.cs @@ -6,6 +6,6 @@ namespace NadekoBot.Attributes public class OwnerOnlyAttribute : PreconditionAttribute { public override Task CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) => - Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); + Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner"))); } } \ No newline at end of file diff --git a/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs b/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs new file mode 100644 index 00000000..a91943d7 --- /dev/null +++ b/src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs @@ -0,0 +1,1385 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170331093025_startup-commands")] + partial class startupcommands + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("DateAdded"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170331093025_startup-commands.cs b/src/NadekoBot/Migrations/20170331093025_startup-commands.cs new file mode 100644 index 00000000..d3cd52a9 --- /dev/null +++ b/src/NadekoBot/Migrations/20170331093025_startup-commands.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class startupcommands : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "StartupCommand", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + BotConfigId = table.Column(nullable: true), + ChannelId = table.Column(nullable: false), + ChannelName = table.Column(nullable: true), + CommandText = table.Column(nullable: true), + DateAdded = table.Column(nullable: true), + GuildId = table.Column(nullable: true), + GuildName = table.Column(nullable: true), + Index = table.Column(nullable: false), + VoiceChannelId = table.Column(nullable: true), + VoiceChannelName = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_StartupCommand", x => x.Id); + table.ForeignKey( + name: "FK_StartupCommand_BotConfig_BotConfigId", + column: x => x.BotConfigId, + principalTable: "BotConfig", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_StartupCommand_BotConfigId", + table: "StartupCommand", + column: "BotConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "StartupCommand"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 97e9b393..83771957 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -950,6 +950,38 @@ namespace NadekoBot.Migrations b.ToTable("SelfAssignableRoles"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => { b.Property("Id") @@ -1288,6 +1320,13 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => { b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 2f076ae3..905243ba 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -32,7 +32,7 @@ namespace NadekoBot.Modules.Administration } - private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd) + private static Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd) { var _ = Task.Run(async () => { diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 89d23094..3af86611 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -10,6 +10,8 @@ using System.Net.Http; using System.Threading.Tasks; using Discord.WebSocket; using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; namespace NadekoBot.Modules.Administration { @@ -31,6 +33,166 @@ namespace NadekoBot.Modules.Administration _forwardDMs = config.ForwardMessages; _forwardDMsToAllOwners = config.ForwardToAllOwners; } + + var _ = Task.Run(async () => + { +#if !GLOBAL_NADEKO + await Task.Delay(2000); +#else + await Task.Delay(10000); +#endif + foreach (var cmd in NadekoBot.BotConfig.StartupCommands) + { + if (cmd.GuildId != null) + { + var guild = NadekoBot.Client.GetGuild(cmd.GuildId.Value); + var channel = guild?.GetChannel(cmd.ChannelId) as SocketTextChannel; + if (channel == null) + continue; + + try + { + var msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false); + //msg.DeleteAfter(5); + } + catch { } + } + } + }); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandAdd([Remainder] string cmdText) + { + var guser = ((IGuildUser)Context.User); + var cmd = new StartupCommand() + { + CommandText = cmdText, + ChannelId = Context.Channel.Id, + ChannelName = Context.Channel.Name, + GuildId = Context.Guild?.Id, + GuildName = Context.Guild?.Name, + VoiceChannelId = guser.VoiceChannel?.Id, + VoiceChannelName = guser.VoiceChannel?.Name, + }; + using (var uow = DbHandler.UnitOfWork()) + { + uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands.Add(cmd); + await uow.CompleteAsync().ConfigureAwait(false); + } + + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() + .WithTitle(GetText("scadd")) + .AddField(efb => efb.WithName(GetText("server")) + .WithValue(cmd.GuildId == null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("channel")) + .WithValue($"{cmd.ChannelName}/{cmd.ChannelId}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("command_text")) + .WithValue(cmdText).WithIsInline(false))); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommands(int page = 1) + { + if (page < 1) + return; + page -= 1; + IEnumerable scmds; + using (var uow = DbHandler.UnitOfWork()) + { + scmds = uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands + .OrderBy(x => x.Id) + .ToArray(); + } + scmds = scmds.Skip(page * 5).Take(5); + if (!scmds.Any()) + { + await ReplyErrorLocalized("startcmdlist_none").ConfigureAwait(false); + } + else + { + await Context.Channel.SendConfirmAsync("", string.Join("\n--\n", scmds.Select(x => + { + string str = Format.Code(GetText("server")) + ": " + (x.GuildId == null ? "-" : x.GuildName + "/" + x.GuildId); + + str += $@" +{Format.Code(GetText("channel"))}: {x.ChannelName}/{x.ChannelId} +{Format.Code(GetText("command_text"))}: {x.CommandText}"; + return str; + })),footer: GetText("page", page + 1)) + .ConfigureAwait(false); + } + } + + [NadekoCommand, Usage, Description, Aliases] + [OwnerOnly] + public async Task Wait(int miliseconds) + { + if (miliseconds <= 0) + return; + Context.Message.DeleteAfter(0); + try + { + var msg = await Context.Channel.SendConfirmAsync($"⏲ {miliseconds}ms") + .ConfigureAwait(false); + msg.DeleteAfter(miliseconds / 1000); + } + catch { } + + await Task.Delay(miliseconds); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandRemove([Remainder] string cmdText) + { + StartupCommand cmd; + using (var uow = DbHandler.UnitOfWork()) + { + var cmds = uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands; + cmd = cmds + .FirstOrDefault(x => x.CommandText.ToLowerInvariant() == cmdText.ToLowerInvariant()); + + if (cmd != null) + { + cmds.Remove(cmd); + await uow.CompleteAsync().ConfigureAwait(false); + } + } + + if(cmd == null) + await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false); + else + await ReplyConfirmLocalized("scrm").ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [OwnerOnly] + public async Task StartupCommandsClear() + { + using (var uow = DbHandler.UnitOfWork()) + { + uow.BotConfig + .GetOrCreate(set => set.Include(x => x.StartupCommands)) + .StartupCommands + .Clear(); + uow.Complete(); + } + + await ReplyConfirmLocalized("startcmds_cleared").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] @@ -68,7 +230,7 @@ namespace NadekoBot.Modules.Administration } - public static async Task HandleDmForwarding(SocketMessage msg, List ownerChannels) + public static async Task HandleDmForwarding(IUserMessage msg, List ownerChannels) { if (_forwardDMs && ownerChannels.Any()) { @@ -157,7 +319,7 @@ namespace NadekoBot.Modules.Administration else { await server.DeleteAsync().ConfigureAwait(false); - await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false); + await ReplyConfirmLocalized("deleted_server", Format.Bold(server.Name)).ConfigureAwait(false); } } @@ -332,4 +494,4 @@ namespace NadekoBot.Modules.Administration } } } -} +} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index ded760c2..f37b864c 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -61,7 +61,10 @@ namespace NadekoBot.Modules.Administration switch (p.Punishment) { case PunishmentAction.Mute: - await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)); + if (p.Time == 0) + await MuteCommands.MuteUser(user).ConfigureAwait(false); + else + await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false); break; case PunishmentAction.Kick: await user.KickAsync().ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index f28a7bc9..ac6fd4c9 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -59,7 +59,7 @@ namespace NadekoBot.Modules.CustomReactions public void ClearStats() => ReactionStats.Clear(); - public static CustomReaction TryGetCustomReaction(SocketUserMessage umsg) + public static CustomReaction TryGetCustomReaction(IUserMessage umsg) { var channel = umsg.Channel as SocketTextChannel; if (channel == null) diff --git a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs index 0e85e4b0..fd426be3 100644 --- a/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/CleverBotCommands.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Games _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } - public static async Task TryAsk(SocketUserMessage msg) + public static async Task TryAsk(IUserMessage msg) { var channel = msg.Channel as ITextChannel; diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 61163a92..20c12253 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -7889,6 +7889,114 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to scadd. + /// + public static string startupcommandadd_cmd { + get { + return ResourceManager.GetString("startupcommandadd_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up.. + /// + public static string startupcommandadd_desc { + get { + return ResourceManager.GetString("startupcommandadd_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scadd .stats`. + /// + public static string startupcommandadd_usage { + get { + return ResourceManager.GetString("startupcommandadd_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to scrm. + /// + public static string startupcommandremove_cmd { + get { + return ResourceManager.GetString("startupcommandremove_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes a startup command with the provided command text.. + /// + public static string startupcommandremove_desc { + get { + return ResourceManager.GetString("startupcommandremove_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scrm .stats`. + /// + public static string startupcommandremove_usage { + get { + return ResourceManager.GetString("startupcommandremove_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to sclist. + /// + public static string startupcommands_cmd { + get { + return ResourceManager.GetString("startupcommands_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Lists all startup commands in the order they will be executed in.. + /// + public static string startupcommands_desc { + get { + return ResourceManager.GetString("startupcommands_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}sclist`. + /// + public static string startupcommands_usage { + get { + return ResourceManager.GetString("startupcommands_usage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to scclr. + /// + public static string startupcommandsclear_cmd { + get { + return ResourceManager.GetString("startupcommandsclear_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Removes all startup commands.. + /// + public static string startupcommandsclear_desc { + get { + return ResourceManager.GetString("startupcommandsclear_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}scclr`. + /// + public static string startupcommandsclear_usage { + get { + return ResourceManager.GetString("startupcommandsclear_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to startwar sw. /// @@ -9131,6 +9239,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to wait. + /// + public static string wait_cmd { + get { + return ResourceManager.GetString("wait_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands.. + /// + public static string wait_desc { + get { + return ResourceManager.GetString("wait_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}wait 3000`. + /// + public static string wait_usage { + get { + return ResourceManager.GetString("wait_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to warn. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index db8b3f50..5d1d0539 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3240,6 +3240,42 @@ `{0}warn @b1nzy` + + scadd + + + Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. + + + `{0}scadd .stats` + + + scrm + + + Removes a startup command with the provided command text. + + + `{0}scrm .stats` + + + scclr + + + Removes all startup commands. + + + `{0}scclr` + + + sclist + + + Lists all startup commands in the order they will be executed in. + + + `{0}sclist` + unban @@ -3249,6 +3285,15 @@ `{0}unban kwoth#1234` or `{0}unban 123123123` + + wait + + + Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. + + + `{0}wait 3000` + warnclear warnc diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 34e12752..ea980b1f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -231,6 +231,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Channel. + /// + public static string administration_channel { + get { + return ResourceManager.GetString("administration_channel", resourceCulture); + } + } + /// /// Looks up a localized string similar to Cleaned up.. /// @@ -240,6 +249,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Command Text. + /// + public static string administration_command_text { + get { + return ResourceManager.GetString("administration_command_text", resourceCulture); + } + } + /// /// Looks up a localized string similar to Content. /// @@ -1233,6 +1251,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to New startup command added.. + /// + public static string administration_scadd { + get { + return ResourceManager.GetString("administration_scadd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup command successfully removed.. + /// + public static string administration_scrm { + get { + return ResourceManager.GetString("administration_scrm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Startup command not found.. + /// + public static string administration_scrm_fail { + get { + return ResourceManager.GetString("administration_scrm_fail", resourceCulture); + } + } + /// /// Looks up a localized string similar to You already have {0} role.. /// @@ -1332,6 +1377,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Server. + /// + public static string administration_server { + get { + return ResourceManager.GetString("administration_server", resourceCulture); + } + } + /// /// Looks up a localized string similar to New avatar set!. /// @@ -1486,6 +1540,24 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to No startup commands on this page.. + /// + public static string administration_startcmdlist_none { + get { + return ResourceManager.GetString("administration_startcmdlist_none", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cleared all startup commands.. + /// + public static string administration_startcmds_cleared { + get { + return ResourceManager.GetString("administration_startcmds_cleared", resourceCulture); + } + } + /// /// Looks up a localized string similar to Text channel created.. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index a94761da..92087d6b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2278,6 +2278,12 @@ Owner ID: {2} Competitive playtime + + Channel + + + Command Text + Moderator @@ -2287,6 +2293,24 @@ Owner ID: {2} Reason + + New startup command added. + + + Startup command successfully removed. + + + Startup command not found. + + + Server + + + No startup commands on this page. + + + Cleared all startup commands. + User {0} has been unbanned. diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 17521cab..31f30932 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -37,7 +37,7 @@ namespace NadekoBot.Services private List ownerChannels { get; set; } = new List(); - public event Func CommandExecuted = delegate { return Task.CompletedTask; }; + public event Func CommandExecuted = delegate { return Task.CompletedTask; }; //userid/msg count public ConcurrentDictionary UserMessagesSent { get; } = new ConcurrentDictionary(); @@ -109,7 +109,7 @@ namespace NadekoBot.Services return Task.CompletedTask; } - private async Task TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild) + private async Task TryRunCleverbot(IUserMessage usrMsg, IGuild guild) { if (guild == null) return false; @@ -130,14 +130,13 @@ namespace NadekoBot.Services return false; } - private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) => - usrMsg.Author?.Id == 193022505026453504 || // he requested to be blacklisted from self-hosted bots + private bool IsBlacklisted(IGuild guild, IUserMessage usrMsg) => (guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) || BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) || BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id); private const float _oneThousandth = 1.0f / 1000; - private Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) + private Task LogSuccessfulExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total) { _log.Info("Command Executed after {4}/{5}/{6}/{7}s\n\t" + "User: {0}\n\t" + @@ -156,7 +155,7 @@ namespace NadekoBot.Services return Task.CompletedTask; } - private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, int exec1, int exec2, int exec3, int total) + private void LogErroredExecution(IUserMessage usrMsg, ExecuteCommandResult exec, ITextChannel channel, int exec1, int exec2, int exec3, int total) { _log.Warn("Command Errored after {5}/{6}/{7}/{8}s\n\t" + "User: {0}\n\t" + @@ -176,7 +175,7 @@ namespace NadekoBot.Services ); } - private async Task InviteFiltered(IGuild guild, SocketUserMessage usrMsg) + private async Task InviteFiltered(IGuild guild, IUserMessage usrMsg) { if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) || Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) && @@ -196,7 +195,7 @@ namespace NadekoBot.Services return false; } - private async Task WordFiltered(IGuild guild, SocketUserMessage usrMsg) + private async Task WordFiltered(IGuild guild, IUserMessage usrMsg) { var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id) ?? new ConcurrentHashSet(); var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id) ?? new ConcurrentHashSet(); @@ -232,8 +231,6 @@ namespace NadekoBot.Services if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized return; - var execTime = Environment.TickCount; - var usrMsg = msg as SocketUserMessage; if (usrMsg == null) //has to be an user message, not system/other messages. return; @@ -248,131 +245,7 @@ namespace NadekoBot.Services var channel = msg.Channel as SocketTextChannel; var guild = channel?.Guild; - if (guild != null && guild.OwnerId != msg.Author.Id) - { - if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) - return; - - if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) - return; - } - - if (IsBlacklisted(guild, usrMsg)) - return; - - var exec1 = Environment.TickCount - execTime; - - var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); - if (cleverBotRan) - return; - - var exec2 = Environment.TickCount - execTime; - - // maybe this message is a custom reaction - // todo log custom reaction executions. return struct with info - var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); - if (cr != null) //if it was, don't execute the command - { - try - { - if (guild != null) - { - PermissionCache pc; - if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) - { - using (var uow = DbHandler.UnitOfWork()) - { - var config = uow.GuildConfigs.For(guild.Id, - set => set.Include(x => x.Permissions)); - Permissions.UpdateCache(config); - } - Permissions.Cache.TryGetValue(guild.Id, out pc); - if (pc == null) - throw new Exception("Cache is null."); - } - int index; - if ( - !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", - out index)) - { - //todo print in guild actually - var returnMsg = - $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; - _log.Info(returnMsg); - return; - } - } - await cr.Send(usrMsg).ConfigureAwait(false); - - if (cr.AutoDeleteTrigger) - { - try { await msg.DeleteAsync().ConfigureAwait(false); } catch { } - } - } - catch (Exception ex) - { - _log.Warn("Sending CREmbed failed"); - _log.Warn(ex); - } - return; - } - - var exec3 = Environment.TickCount - execTime; - - string messageContent = usrMsg.Content; - if (guild != null) - { - ConcurrentDictionary maps; - if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) - { - string newMessageContent; - if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) - { - _log.Info(@"--Mapping Command-- - GuildId: {0} - Trigger: {1} - Mapping: {2}", guild.Id, messageContent, newMessageContent); - var oldMessageContent = messageContent; - messageContent = newMessageContent; - - try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } - } - } - } - - - // execute the command and measure the time it took - var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); - execTime = Environment.TickCount - execTime; - - if (exec.Result.IsSuccess) - { - await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); - await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false); - } - else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) - { - LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime); - if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) - { - if (exec.PermissionCache != null && exec.PermissionCache.Verbose) - try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } - } - } - else - { - if (msg.Channel is IPrivateChannel) - { - // rofl, gotta do this to prevent dm help message being sent to - // users who are voting on private polls (sending a number in a DM) - int vote; - if (int.TryParse(msg.Content, out vote)) return; - - await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); - - await SelfCommands.HandleDmForwarding(msg, ownerChannels).ConfigureAwait(false); - } - } + await TryRunCommand(guild, channel, usrMsg); } catch (Exception ex) { @@ -388,6 +261,137 @@ namespace NadekoBot.Services return Task.CompletedTask; } + public async Task TryRunCommand(SocketGuild guild, ITextChannel channel, IUserMessage usrMsg) + { + var execTime = Environment.TickCount; + + if (guild != null && guild.OwnerId != usrMsg.Author.Id) + { + if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + + if (await WordFiltered(guild, usrMsg).ConfigureAwait(false)) + return; + } + + if (IsBlacklisted(guild, usrMsg)) + return; + + var exec1 = Environment.TickCount - execTime; + + var cleverBotRan = await Task.Run(() => TryRunCleverbot(usrMsg, guild)).ConfigureAwait(false); + if (cleverBotRan) + return; + + var exec2 = Environment.TickCount - execTime; + + // maybe this message is a custom reaction + // todo log custom reaction executions. return struct with info + var cr = await Task.Run(() => CustomReactions.TryGetCustomReaction(usrMsg)).ConfigureAwait(false); + if (cr != null) //if it was, don't execute the command + { + try + { + if (guild != null) + { + PermissionCache pc; + if (!Permissions.Cache.TryGetValue(guild.Id, out pc)) + { + using (var uow = DbHandler.UnitOfWork()) + { + var config = uow.GuildConfigs.For(guild.Id, + set => set.Include(x => x.Permissions)); + Permissions.UpdateCache(config); + } + Permissions.Cache.TryGetValue(guild.Id, out pc); + if (pc == null) + throw new Exception("Cache is null."); + } + int index; + if ( + !pc.Permissions.CheckPermissions(usrMsg, cr.Trigger, "ActualCustomReactions", + out index)) + { + //todo print in guild actually + var returnMsg = + $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(guild)}** is preventing this action."; + _log.Info(returnMsg); + return; + } + } + await cr.Send(usrMsg).ConfigureAwait(false); + + if (cr.AutoDeleteTrigger) + { + try { await usrMsg.DeleteAsync().ConfigureAwait(false); } catch { } + } + } + catch (Exception ex) + { + _log.Warn("Sending CREmbed failed"); + _log.Warn(ex); + } + return; + } + + var exec3 = Environment.TickCount - execTime; + + string messageContent = usrMsg.Content; + if (guild != null) + { + ConcurrentDictionary maps; + if (Modules.Utility.Utility.CommandMapCommands.AliasMaps.TryGetValue(guild.Id, out maps)) + { + string newMessageContent; + if (maps.TryGetValue(messageContent.Trim().ToLowerInvariant(), out newMessageContent)) + { + _log.Info(@"--Mapping Command-- + GuildId: {0} + Trigger: {1} + Mapping: {2}", guild.Id, messageContent, newMessageContent); + var oldMessageContent = messageContent; + messageContent = newMessageContent; + + try { await usrMsg.Channel.SendConfirmAsync($"{oldMessageContent} => {newMessageContent}").ConfigureAwait(false); } catch { } + } + } + } + + + // execute the command and measure the time it took + var exec = await Task.Run(() => ExecuteCommand(new CommandContext(_client, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best)).ConfigureAwait(false); + execTime = Environment.TickCount - execTime; + + if (exec.Result.IsSuccess) + { + await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false); + await LogSuccessfulExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime).ConfigureAwait(false); + } + else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand) + { + LogErroredExecution(usrMsg, exec, channel, exec1, exec2, exec3, execTime); + if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception) + { + if (exec.PermissionCache != null && exec.PermissionCache.Verbose) + try { await usrMsg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { } + } + } + else + { + if (usrMsg.Channel is IPrivateChannel) + { + // rofl, gotta do this to prevent dm help message being sent to + // users who are voting on private polls (sending a number in a DM) + int vote; + if (int.TryParse(usrMsg.Content, out vote)) return; + + await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false); + + await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false); + } + } + } + public Task ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception) => ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling); diff --git a/src/NadekoBot/Services/Database/Models/BotConfig.cs b/src/NadekoBot/Services/Database/Models/BotConfig.cs index 8ff90e8a..b25dc744 100644 --- a/src/NadekoBot/Services/Database/Models/BotConfig.cs +++ b/src/NadekoBot/Services/Database/Models/BotConfig.cs @@ -61,6 +61,19 @@ Nadeko Support Server: https://discord.gg/nadekobot"; public string OkColor { get; set; } = "71cd40"; public string ErrorColor { get; set; } = "ee281f"; public string Locale { get; set; } = null; + public List StartupCommands { get; set; } + } + + public class StartupCommand : DbEntity, IIndexed + { + public int Index { get; set; } + public string CommandText { get; set; } + public ulong ChannelId { get; set; } + public string ChannelName { get; set; } + public ulong? GuildId { get; set; } + public string GuildName { get; set; } + public ulong? VoiceChannelId { get; set; } + public string VoiceChannelName { get; set; } } public class PlayingStatus :DbEntity diff --git a/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs index 7f9f3dd5..7a2adf63 100644 --- a/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IBotConfigRepository.cs @@ -1,9 +1,12 @@ -using NadekoBot.Services.Database.Models; +using Microsoft.EntityFrameworkCore; +using NadekoBot.Services.Database.Models; +using System; +using System.Linq; namespace NadekoBot.Services.Database.Repositories { public interface IBotConfigRepository : IRepository { - BotConfig GetOrCreate(); + BotConfig GetOrCreate(Func, IQueryable> includes = null); } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs index 2aa0bf83..1e40f86c 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/BotConfigRepository.cs @@ -1,6 +1,7 @@ using NadekoBot.Services.Database.Models; using System.Linq; using Microsoft.EntityFrameworkCore; +using System; namespace NadekoBot.Services.Database.Repositories.Impl { @@ -10,15 +11,21 @@ namespace NadekoBot.Services.Database.Repositories.Impl { } - public BotConfig GetOrCreate() + public BotConfig GetOrCreate(Func, IQueryable> includes = null) { - var config = _set.Include(bc => bc.RotatingStatusMessages) + BotConfig config; + + if (includes == null) + config = _set.Include(bc => bc.RotatingStatusMessages) .Include(bc => bc.RaceAnimals) .Include(bc => bc.Blacklist) .Include(bc => bc.EightBallResponses) .Include(bc => bc.ModulePrefixes) + .Include(bc => bc.StartupCommands) //.Include(bc => bc.CommandCosts) .FirstOrDefault(); + else + config = includes(_set).FirstOrDefault(); if (config == null) { From 223b668628c6691a0b1f8fb1f731f58ffbfe3352 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 11:15:37 +0200 Subject: [PATCH 16/26] softban is a separate punishment from kick now. Commandlist updated --- .../Modules/Administration/Commands/LogCommand.cs | 3 +++ .../Administration/Commands/ProtectionCommands.cs | 7 +++++++ .../Administration/Commands/UserPunishCommands.cs | 11 +++++++++++ src/NadekoBot/Resources/ResponseStrings.Designer.cs | 11 ++++++++++- src/NadekoBot/Resources/ResponseStrings.resx | 6 +++++- .../Services/Database/Models/AntiProtection.cs | 1 + 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs index f061f045..515c2f46 100644 --- a/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/LogCommand.cs @@ -307,6 +307,9 @@ namespace NadekoBot.Modules.Administration punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant(); break; case PunishmentAction.Kick: + punishment = "👢 " + logChannel.Guild.GetLogText("kicked_pl").ToUpperInvariant(); + break; + case PunishmentAction.Softban: punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant(); break; case PunishmentAction.Ban: diff --git a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs index af7269c9..23f1eaf0 100644 --- a/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/ProtectionCommands.cs @@ -188,6 +188,13 @@ namespace NadekoBot.Modules.Administration catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } break; case PunishmentAction.Kick: + try + { + await gu.KickAsync().ConfigureAwait(false); + } + catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); } + break; + case PunishmentAction.Softban: try { await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false); diff --git a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs index f37b864c..f794d47a 100644 --- a/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/UserPunishCommands.cs @@ -72,6 +72,17 @@ namespace NadekoBot.Modules.Administration case PunishmentAction.Ban: await guild.AddBanAsync(user).ConfigureAwait(false); break; + case PunishmentAction.Softban: + await guild.AddBanAsync(user).ConfigureAwait(false); + try + { + await guild.RemoveBanAsync(user).ConfigureAwait(false); + } + catch + { + await guild.RemoveBanAsync(user).ConfigureAwait(false); + } + break; default: break; } diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index ea980b1f..3d91002f 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -574,6 +574,15 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Kicked. + /// + public static string administration_kicked_pl { + get { + return ResourceManager.GetString("administration_kicked_pl", resourceCulture); + } + } + /// /// Looks up a localized string similar to User kicked. /// @@ -1504,7 +1513,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to soft-banned (kicked). + /// Looks up a localized string similar to soft-banned. /// public static string administration_soft_banned_pl { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 92087d6b..c71eea89 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -740,7 +740,7 @@ Reason: {1} Slow mode initiated - soft-banned (kicked) + soft-banned PLURAL @@ -2284,6 +2284,10 @@ Owner ID: {2} Command Text + + Kicked + PLURAL + Moderator diff --git a/src/NadekoBot/Services/Database/Models/AntiProtection.cs b/src/NadekoBot/Services/Database/Models/AntiProtection.cs index 0172dd90..a90ee649 100644 --- a/src/NadekoBot/Services/Database/Models/AntiProtection.cs +++ b/src/NadekoBot/Services/Database/Models/AntiProtection.cs @@ -31,6 +31,7 @@ namespace NadekoBot.Services.Database.Models Mute, Kick, Ban, + Softban } public class AntiSpamIgnore : DbEntity From 83dbc562af0c74dc1d19f756f80f5c5b7a700657 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 11:15:54 +0200 Subject: [PATCH 17/26] Woops --- docs/Commands List.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/docs/Commands List.md b/docs/Commands List.md index 0ce3438d..715df776 100644 --- a/docs/Commands List.md +++ b/docs/Commands List.md @@ -26,9 +26,6 @@ Commands and aliases | Description | Usage `.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User` `.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role` `.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55` -`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.` -`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.` -`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.` `.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"` `.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"` `.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName` @@ -73,6 +70,11 @@ Commands and aliases | Description | Usage `.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` +`.scadd` | Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. **Bot owner only** | `.scadd .stats` +`.sclist` | Lists all startup commands in the order they will be executed in. **Bot owner only** | `.sclist` +`.wait` | Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. **Bot owner only** | `.wait 3000` +`.scrm` | Removes a startup command with the provided command text. **Bot owner only** | `.scrm .stats` +`.scclr` | Removes all startup commands. **Bot owner only** | `.scclr` `.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs` `.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall` `.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2` @@ -94,6 +96,15 @@ Commands and aliases | Description | Usage `.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye` `.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.` `.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30` +`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy` +`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy` +`.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude` +`.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3` +`.warnpunishlist` `.warnpl` | Lists punishments for warnings. | `.warnpunishlist` +`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.` +`.unban` | Unbans a user with the provided user#discrim or id. **Requires BanMembers server permission.** | `.unban kwoth#1234` or `.unban 123123123` +`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.` +`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.` `.vcrole` | Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.vcrole SomeRole` or `.vcrole` `.vcrolelist` | Shows a list of currently set voice channel roles. | `.vcrolelist` `.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t` From 3a5aed213b3580521e2a0a9f9bb5e6299ffcf622 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 13:47:05 +0200 Subject: [PATCH 18/26] startup commands will no longer be treated as if theyr'e run in DMs --- .../Commands/RatelimitCommand.cs | 27 +++++++++++++++++++ .../Administration/Commands/SelfCommands.cs | 11 ++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 2a4e111f..6d1e3f13 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -1,7 +1,10 @@ using Discord; using Discord.Commands; +using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; using NLog; using System; using System.Collections.Concurrent; @@ -118,6 +121,30 @@ namespace NadekoBot.Modules.Administration .ConfigureAwait(false); } } + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //[RequireUserPermission(GuildPermission.ManageMessages)] + //public async Task SlowmodeWhitelist(IUser user) + //{ + // Ratelimiter throwaway; + // if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway)) + // { + // throwaway.cancelSource.Cancel(); + // await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false); + // } + //} + + //[NadekoCommand, Usage, Description, Aliases] + //[RequireContext(ContextType.Guild)] + //[RequireUserPermission(GuildPermission.ManageMessages)] + //public async Task SlowmodeWhitelist(IRole role) + //{ + // using (var uow = DbHandler.UnitOfWork()) + // { + // uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeWhitelists)). + // } + //} } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 3af86611..09924682 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -36,11 +36,9 @@ namespace NadekoBot.Modules.Administration var _ = Task.Run(async () => { -#if !GLOBAL_NADEKO - await Task.Delay(2000); -#else - await Task.Delay(10000); -#endif + while(!NadekoBot.Ready) + await Task.Delay(1000); + foreach (var cmd in NadekoBot.BotConfig.StartupCommands) { if (cmd.GuildId != null) @@ -52,7 +50,8 @@ namespace NadekoBot.Modules.Administration try { - var msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + IUserMessage msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false); + msg = (IUserMessage)await channel.GetMessageAsync(msg.Id).ConfigureAwait(false); await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false); //msg.DeleteAfter(5); } From 2b65518649b6b338cfde0d9d6468fae50ec5f585 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 21:40:13 +0200 Subject: [PATCH 19/26] Slowmode whitelists done, need testing --- ...70401161600_slowmode-whitelist.Designer.cs | 1435 +++++++++++++++++ .../20170401161600_slowmode-whitelist.cs | 73 + .../NadekoSqliteContextModelSnapshot.cs | 50 + .../Commands/RatelimitCommand.cs | 112 +- .../Utility/Commands/PatreonCommands.cs | 113 +- .../Resources/CommandStrings.Designer.cs | 54 + src/NadekoBot/Resources/CommandStrings.resx | 18 + .../Resources/ResponseStrings.Designer.cs | 117 ++ src/NadekoBot/Resources/ResponseStrings.resx | 39 + .../Services/Database/Models/GuildConfig.cs | 46 + .../Services/Database/Models/RewardedUser.cs | 11 + 11 files changed, 2020 insertions(+), 48 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs create mode 100644 src/NadekoBot/Services/Database/Models/RewardedUser.cs diff --git a/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs new file mode 100644 index 00000000..7409d096 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs @@ -0,0 +1,1435 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170401161600_slowmode-whitelist")] + partial class slowmodewhitelist + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("DateAdded"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs new file mode 100644 index 00000000..fc2be484 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class slowmodewhitelist : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "SlowmodeIgnoredRole", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + RoleId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SlowmodeIgnoredRole", x => x.Id); + table.ForeignKey( + name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateTable( + name: "SlowmodeIgnoredUser", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + DateAdded = table.Column(nullable: true), + GuildConfigId = table.Column(nullable: true), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_SlowmodeIgnoredUser", x => x.Id); + table.ForeignKey( + name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId", + column: x => x.GuildConfigId, + principalTable: "GuildConfigs", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_SlowmodeIgnoredRole_GuildConfigId", + table: "SlowmodeIgnoredRole", + column: "GuildConfigId"); + + migrationBuilder.CreateIndex( + name: "IX_SlowmodeIgnoredUser_GuildConfigId", + table: "SlowmodeIgnoredUser", + column: "GuildConfigId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "SlowmodeIgnoredRole"); + + migrationBuilder.DropTable( + name: "SlowmodeIgnoredUser"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 83771957..3f6df376 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -950,6 +950,42 @@ namespace NadekoBot.Migrations b.ToTable("SelfAssignableRoles"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => { b.Property("Id") @@ -1320,6 +1356,20 @@ namespace NadekoBot.Migrations .HasForeignKey("BotConfigId"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => { b.HasOne("NadekoBot.Services.Database.Models.BotConfig") diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 6d1e3f13..0c0f91be 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -1,13 +1,17 @@ using Discord; using Discord.Commands; +using Discord.WebSocket; using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; using NLog; using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -23,6 +27,9 @@ namespace NadekoBot.Modules.Administration public class Ratelimiter { + public HashSet IgnoreUsers { get; set; } = new HashSet(); + public HashSet IgnoreRoles { get; set; } = new HashSet(); + public class RatelimitedUser { public ulong UserId { get; set; } @@ -38,10 +45,14 @@ namespace NadekoBot.Modules.Administration public ConcurrentDictionary Users { get; set; } = new ConcurrentDictionary(); - public bool CheckUserRatelimit(ulong id) + public bool CheckUserRatelimit(ulong id, SocketGuildUser optUser) { + if (IgnoreUsers.Contains(id) || + (optUser != null && optUser.RoleIds.Any(x => IgnoreRoles.Contains(x)))) + return false; + var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); - if (usr.MessageCount == MaxMessages) + if (usr.MessageCount >= MaxMessages) { return true; } @@ -67,8 +78,8 @@ namespace NadekoBot.Modules.Administration { try { - var usrMsg = umsg as IUserMessage; - var channel = usrMsg?.Channel as ITextChannel; + var usrMsg = umsg as SocketUserMessage; + var channel = usrMsg?.Channel as SocketTextChannel; if (channel == null || usrMsg.IsAuthor()) return; @@ -76,7 +87,7 @@ namespace NadekoBot.Modules.Administration if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter)) return; - if (limiter.CheckUserRatelimit(usrMsg.Author.Id)) + if (limiter.CheckUserRatelimit(usrMsg.Author.Id, usrMsg.Author as SocketGuildUser)) await usrMsg.DeleteAsync(); } catch (Exception ex) { _log.Warn(ex); } @@ -122,29 +133,76 @@ namespace NadekoBot.Modules.Administration } } - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //[RequireUserPermission(GuildPermission.ManageMessages)] - //public async Task SlowmodeWhitelist(IUser user) - //{ - // Ratelimiter throwaway; - // if (RatelimitingChannels.TryRemove(Context.Channel.Id, out throwaway)) - // { - // throwaway.cancelSource.Cancel(); - // await ReplyConfirmLocalized("slowmode_disabled").ConfigureAwait(false); - // } - //} + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(1)] + public async Task SlowmodeWhitelist(IUser user) + { + var siu = new SlowmodeIgnoredUser + { + UserId = user.Id + }; - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //[RequireUserPermission(GuildPermission.ManageMessages)] - //public async Task SlowmodeWhitelist(IRole role) - //{ - // using (var uow = DbHandler.UnitOfWork()) - // { - // uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeWhitelists)). - // } - //} + HashSet usrs; + bool removed; + using (var uow = DbHandler.UnitOfWork()) + { + usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers)) + .SlowmodeIgnoredUsers; + + if (!(removed = usrs.Remove(siu))) + usrs.Add(siu); + + await uow.CompleteAsync().ConfigureAwait(false); + } + + Ratelimiter rl; + if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) + { + rl.IgnoreUsers = new HashSet(usrs.Select(x => x.UserId)); + } + if(removed) + await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false); + else + await ReplyConfirmLocalized("slowmodewl_user_start", Format.Bold(user.ToString())).ConfigureAwait(false); + } + + [NadekoCommand, Usage, Description, Aliases] + [RequireContext(ContextType.Guild)] + [RequireUserPermission(GuildPermission.ManageMessages)] + [Priority(0)] + public async Task SlowmodeWhitelist(IRole role) + { + var sir = new SlowmodeIgnoredRole + { + RoleId = role.Id + }; + + HashSet roles; + bool removed; + using (var uow = DbHandler.UnitOfWork()) + { + roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles)) + .SlowmodeIgnoredRoles; + + if (!(removed = roles.Remove(sir))) + roles.Add(sir); + + await uow.CompleteAsync().ConfigureAwait(false); + } + + Ratelimiter rl; + if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) + { + rl.IgnoreRoles = new HashSet(roles.Select(x => x.RoleId)); + } + + if (removed) + await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false); + else + await ReplyConfirmLocalized("slowmodewl_role_start", Format.Bold(role.ToString())).ConfigureAwait(false); + } } } } \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index c8908abe..76dd9ee0 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -9,6 +9,9 @@ //using System.Threading; //using System; //using System.Collections.Immutable; +//using NadekoBot.Services; +//using NadekoBot.Services.Database.Models; +//using NadekoBot.Extensions; //namespace NadekoBot.Modules.Utility //{ @@ -17,20 +20,45 @@ // [Group] // public class PatreonCommands : NadekoSubmodule // { +// private static readonly PatreonThingy patreon; + +// static PatreonCommands() +// { +// patreon = PatreonThingy.Instance; +// } // [NadekoCommand, Usage, Description, Aliases] // public async Task ClaimPatreonRewards() // { -// var patreon = PatreonThingy.Instance; - -// var pledges = (await patreon.GetPledges().ConfigureAwait(false)) -// .OrderByDescending(x => x.Reward.attributes.amount_cents); - -// if (pledges == null) +// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) +// return; +// if (DateTime.UtcNow.Day < 5) // { -// await ReplyErrorLocalized("pledges_loading").ConfigureAwait(false); +// await ReplyErrorLocalized("claimpatreon_too_early").ConfigureAwait(false); +// } +// int amount = 0; +// try +// { +// amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); +// } +// catch (Exception ex) +// { +// _log.Warn(ex); +// } + +// if (amount > 0) +// { +// await ReplyConfirmLocalized("claimpatreon_success", amount).ConfigureAwait(false); // return; // } +// await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() +// .WithDescription(GetText("claimpatreon_fail")) +// .AddField(efb => efb.WithName("").WithValue("")) +// .AddField(efb => efb.WithName("").WithValue("")) +// .AddField(efb => efb.WithName("").WithValue(""))) +// .ConfigureAwait(false); + +// await ReplyErrorLocalized("claimpatreon_fail").ConfigureAwait(false); // } // } @@ -41,21 +69,16 @@ // private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); -// private ImmutableArray pledges; +// public ImmutableArray Pledges { get; private set; } -// static PatreonThingy() { } +// private readonly Timer update; +// private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); -// public async Task> GetPledges() +// private PatreonThingy() // { -// try -// { -// await LoadPledges().ConfigureAwait(false); -// return pledges; -// } -// catch (OperationCanceledException) -// { -// return pledges; -// } +// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) +// return; +// update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); // } // public async Task LoadPledges() @@ -89,7 +112,7 @@ // .Select(x => JsonConvert.DeserializeObject(x.ToString()))); // } while (!string.IsNullOrWhiteSpace(data.Links.next)); // } -// pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() +// Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() // { // User = y, // Reward = x, @@ -102,7 +125,55 @@ // await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); // getPledgesLocker.Release(); // }); - + +// } +// } + +// public async Task ClaimReward(ulong userId) +// { +// await claimLockJustInCase.WaitAsync(); +// try +// { +// var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + +// if (data == null) +// return 0; + +// var amount = data.Reward.attributes.amount_cents; + +// using (var uow = DbHandler.UnitOfWork()) +// { +// var users = uow._context.Set(); +// var usr = users.FirstOrDefault(x => x.UserId == userId); + +// if (usr == null) +// { +// users.Add(new RewardedUser() +// { +// UserId = userId, +// LastReward = DateTime.UtcNow, +// AmountRewardedThisMonth = amount, +// }); +// await uow.CompleteAsync().ConfigureAwait(false); +// return amount; +// } + +// if (usr.AmountRewardedThisMonth < amount) +// { +// var toAward = amount - usr.AmountRewardedThisMonth; + +// usr.LastReward = DateTime.UtcNow; +// usr.AmountRewardedThisMonth = amount; + +// await uow.CompleteAsync().ConfigureAwait(false); +// return toAward; +// } +// } +// return 0; +// } +// finally +// { +// claimLockJustInCase.Release(); // } // } // } diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index 20c12253..ef7c365a 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1706,6 +1706,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to claimpatreonrewards. + /// + public static string claimpatreonrewards_cmd { + get { + return ResourceManager.GetString("claimpatreonrewards_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. + /// + public static string claimpatreonrewards_desc { + get { + return ResourceManager.GetString("claimpatreonrewards_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}claimpatreonrewards`. + /// + public static string claimpatreonrewards_usage { + get { + return ResourceManager.GetString("claimpatreonrewards_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to cleanup. /// @@ -7673,6 +7700,33 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to slowmodewl. + /// + public static string slowmodewhitelist_cmd { + get { + return ResourceManager.GetString("slowmodewhitelist_cmd", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Ignores a role or a user from the slowmode feature.. + /// + public static string slowmodewhitelist_desc { + get { + return ResourceManager.GetString("slowmodewhitelist_desc", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude`. + /// + public static string slowmodewhitelist_usage { + get { + return ResourceManager.GetString("slowmodewhitelist_usage", resourceCulture); + } + } + /// /// Looks up a localized string similar to softban sb. /// diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 5d1d0539..64236de1 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3321,4 +3321,22 @@ `{0}warnpunish 5 Ban` or `{0}warnpunish 3` + + claimpatreonrewards + + + If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. + + + `{0}claimpatreonrewards` + + + slowmodewl + + + Ignores a role or a user from the slowmode feature. + + + `{0}slowmodewl SomeRole` or `{0}slowmodewl AdminDude` + \ No newline at end of file diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 3d91002f..5befa0b0 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1512,6 +1512,42 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Slowmode will now ignore role {0}. + /// + public static string administration_slowmodewl_role_start { + get { + return ResourceManager.GetString("administration_slowmodewl_role_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will no longer ignore role {0}. + /// + public static string administration_slowmodewl_role_stop { + get { + return ResourceManager.GetString("administration_slowmodewl_role_stop", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will now ignore user {0}. + /// + public static string administration_slowmodewl_user_start { + get { + return ResourceManager.GetString("administration_slowmodewl_user_start", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Slowmode will no longer ignore user {0}. + /// + public static string administration_slowmodewl_user_stop { + get { + return ResourceManager.GetString("administration_slowmodewl_user_stop", resourceCulture); + } + } + /// /// Looks up a localized string similar to soft-banned. /// @@ -5989,6 +6025,87 @@ namespace NadekoBot.Resources { } } + /// + /// Looks up a localized string similar to Failed claiming rewards due to one of the following reasons:. + /// + public static string utility_claimpatreon_fail { + get { + return ResourceManager.GetString("utility_claimpatreon_fail", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. + /// + public static string utility_claimpatreon_fail_already { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_already", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Already rewarded. + /// + public static string utility_claimpatreon_fail_already_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_already_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. + /// + public static string utility_claimpatreon_fail_sup { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_sup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not supporting. + /// + public static string utility_claimpatreon_fail_sup_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_sup_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. + /// + public static string utility_claimpatreon_fail_wait { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_wait", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wait some time. + /// + public static string utility_claimpatreon_fail_wait_title { + get { + return ResourceManager.GetString("utility_claimpatreon_fail_wait_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. + /// + public static string utility_claimpatreon_success { + get { + return ResourceManager.GetString("utility_claimpatreon_success", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Rewards can be claimed on or after 5th of each month.. + /// + public static string utility_claimpatreon_too_early { + get { + return ResourceManager.GetString("utility_claimpatreon_too_early", resourceCulture); + } + } + /// /// Looks up a localized string similar to Commands ran. /// diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index c71eea89..0a523218 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2357,4 +2357,43 @@ Owner ID: {2} I will apply {0} punishment to users with {1} warnings. + + Slowmode will now ignore role {0} + + + Slowmode will no longer ignore role {0} + + + Slowmode will now ignore user {0} + + + Slowmode will no longer ignore user {0} + + + Failed claiming rewards due to one of the following reasons: + + + Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + + + Already rewarded + + + In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. + + + Not supporting + + + You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. + + + Wait some time + + + You've received {0}. Thanks for supporting the project! + + + Rewards can be claimed on or after 5th of each month. + \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/GuildConfig.cs b/src/NadekoBot/Services/Database/Models/GuildConfig.cs index 4fe497c1..aaf7addf 100644 --- a/src/NadekoBot/Services/Database/Models/GuildConfig.cs +++ b/src/NadekoBot/Services/Database/Models/GuildConfig.cs @@ -73,10 +73,56 @@ namespace NadekoBot.Services.Database.Models public HashSet CommandAliases { get; set; } = new HashSet(); public List WarnPunishments { get; set; } = new List(); public bool WarningsInitialized { get; set; } + public HashSet SlowmodeIgnoredUsers { get; set; } + public HashSet SlowmodeIgnoredRoles { get; set; } //public List ProtectionIgnoredChannels { get; set; } = new List(); } + public class SlowmodeIgnoredUser : DbEntity + { + public ulong UserId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + return ((SlowmodeIgnoredUser)obj).UserId == UserId; + } + + // override object.GetHashCode + public override int GetHashCode() + { + return UserId.GetHashCode(); + } + } + + public class SlowmodeIgnoredRole : DbEntity + { + public ulong RoleId { get; set; } + + // override object.Equals + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + + return ((SlowmodeIgnoredRole)obj).RoleId == RoleId; + } + + // override object.GetHashCode + public override int GetHashCode() + { + return RoleId.GetHashCode(); + } + } + public class WarningPunishment : DbEntity { public int Count { get; set; } diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs new file mode 100644 index 00000000..e71843b1 --- /dev/null +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -0,0 +1,11 @@ +//using System; + +//namespace NadekoBot.Services.Database.Models +//{ +// public class RewardedUser +// { +// public ulong UserId { get; set; } +// public int AmountRewardedThisMonth { get; set; } +// public DateTime LastReward { get; set; } +// } +//} From 7e23877fd8784082329c488a9c2daa1cb677bef3 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sat, 1 Apr 2017 21:51:25 +0200 Subject: [PATCH 20/26] .clparew (Claim patreon rewards) added, needs testing --- .../Utility/Commands/PatreonCommands.cs | 324 +++++++++--------- .../Resources/CommandStrings.Designer.cs | 4 +- src/NadekoBot/Resources/CommandStrings.resx | 4 +- .../Resources/ResponseStrings.Designer.cs | 36 +- src/NadekoBot/Resources/ResponseStrings.resx | 18 +- .../Services/Database/Models/RewardedUser.cs | 20 +- 6 files changed, 204 insertions(+), 202 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 76dd9ee0..6415dd8f 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -1,181 +1,183 @@ -//using System.Collections.Generic; -//using System.Linq; -//using System.Net.Http; -//using System.Threading.Tasks; -//using Discord.Commands; -//using NadekoBot.Attributes; -//using NadekoBot.Modules.Utility.Models; -//using Newtonsoft.Json; -//using System.Threading; -//using System; -//using System.Collections.Immutable; -//using NadekoBot.Services; -//using NadekoBot.Services.Database.Models; -//using NadekoBot.Extensions; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Modules.Utility.Models; +using Newtonsoft.Json; +using System.Threading; +using System; +using System.Collections.Immutable; +using NadekoBot.Services; +using NadekoBot.Services.Database.Models; +using NadekoBot.Extensions; -//namespace NadekoBot.Modules.Utility -//{ -// public partial class Utility -// { -// [Group] -// public class PatreonCommands : NadekoSubmodule -// { -// private static readonly PatreonThingy patreon; +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + [Group] + public class PatreonCommands : NadekoSubmodule + { + private static readonly PatreonThingy patreon; -// static PatreonCommands() -// { -// patreon = PatreonThingy.Instance; -// } -// [NadekoCommand, Usage, Description, Aliases] -// public async Task ClaimPatreonRewards() -// { -// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) -// return; -// if (DateTime.UtcNow.Day < 5) -// { -// await ReplyErrorLocalized("claimpatreon_too_early").ConfigureAwait(false); -// } -// int amount = 0; -// try -// { -// amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); -// } -// catch (Exception ex) -// { -// _log.Warn(ex); -// } + static PatreonCommands() + { + patreon = PatreonThingy.Instance; + } + [NadekoCommand, Usage, Description, Aliases] + public async Task ClaimPatreonRewards() + { + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) + return; + if (DateTime.UtcNow.Day < 5) + { + await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + } + int amount = 0; + try + { + amount = await patreon.ClaimReward(Context.User.Id).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Warn(ex); + } -// if (amount > 0) -// { -// await ReplyConfirmLocalized("claimpatreon_success", amount).ConfigureAwait(false); -// return; -// } + if (amount > 0) + { + await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); + return; + } -// await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() -// .WithDescription(GetText("claimpatreon_fail")) -// .AddField(efb => efb.WithName("").WithValue("")) -// .AddField(efb => efb.WithName("").WithValue("")) -// .AddField(efb => efb.WithName("").WithValue(""))) -// .ConfigureAwait(false); + await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() + .WithDescription(GetText("clpa_fail")) + .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_wait_title")).WithValue(GetText("clpa_fail_wait"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup")))) + .ConfigureAwait(false); + } + } -// await ReplyErrorLocalized("claimpatreon_fail").ConfigureAwait(false); -// } -// } + public class PatreonThingy + { + public static PatreonThingy _instance = new PatreonThingy(); + public static PatreonThingy Instance => _instance; -// public class PatreonThingy -// { -// public static PatreonThingy _instance = new PatreonThingy(); -// public static PatreonThingy Instance => _instance; + private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); -// private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); + public ImmutableArray Pledges { get; private set; } -// public ImmutableArray Pledges { get; private set; } + private readonly Timer update; + private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); -// private readonly Timer update; -// private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); + private PatreonThingy() + { + if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) + return; + update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); + } -// private PatreonThingy() -// { -// if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) -// return; -// update = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, TimeSpan.FromHours(3)); -// } + public async Task LoadPledges() + { + await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); + try + { + var rewards = new List(); + var users = new List(); + using (var http = new HttpClient()) + { + http.DefaultRequestHeaders.Clear(); + http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); + var data = new PatreonData() + { + Links = new PatreonDataLinks() + { + next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" + } + }; + do + { + var res = await http.GetStringAsync(data.Links.next) + .ConfigureAwait(false); + data = JsonConvert.DeserializeObject(res); + var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); + rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) + .Where(x => x.attributes.declined_since == null)); + users.AddRange(data.Included + .Where(x => x["type"].ToString() == "user") + .Select(x => JsonConvert.DeserializeObject(x.ToString()))); + } while (!string.IsNullOrWhiteSpace(data.Links.next)); + } + Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() + { + User = y, + Reward = x, + }).ToImmutableArray(); + } + finally + { + var _ = Task.Run(async () => + { + await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); + getPledgesLocker.Release(); + }); + } + } -// public async Task LoadPledges() -// { -// await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); -// try -// { -// var rewards = new List(); -// var users = new List(); -// using (var http = new HttpClient()) -// { -// http.DefaultRequestHeaders.Clear(); -// http.DefaultRequestHeaders.Add("Authorization", "Bearer " + NadekoBot.Credentials.PatreonAccessToken); -// var data = new PatreonData() -// { -// Links = new PatreonDataLinks() -// { -// next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" -// } -// }; -// do -// { -// var res = await http.GetStringAsync(data.Links.next) -// .ConfigureAwait(false); -// data = JsonConvert.DeserializeObject(res); -// var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); -// rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) -// .Where(x => x.attributes.declined_since == null)); -// users.AddRange(data.Included -// .Where(x => x["type"].ToString() == "user") -// .Select(x => JsonConvert.DeserializeObject(x.ToString()))); -// } while (!string.IsNullOrWhiteSpace(data.Links.next)); -// } -// Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() -// { -// User = y, -// Reward = x, -// }).ToImmutableArray(); -// } -// finally -// { -// var _ = Task.Run(async () => -// { -// await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); -// getPledgesLocker.Release(); -// }); + public async Task ClaimReward(ulong userId) + { + await claimLockJustInCase.WaitAsync(); + try + { + var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); -// } -// } + if (data == null) + return 0; -// public async Task ClaimReward(ulong userId) -// { -// await claimLockJustInCase.WaitAsync(); -// try -// { -// var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + var amount = data.Reward.attributes.amount_cents; -// if (data == null) -// return 0; + using (var uow = DbHandler.UnitOfWork()) + { + var users = uow._context.Set(); + var usr = users.FirstOrDefault(x => x.UserId == userId); -// var amount = data.Reward.attributes.amount_cents; + if (usr == null) + { + users.Add(new RewardedUser() + { + UserId = userId, + LastReward = DateTime.UtcNow, + AmountRewardedThisMonth = amount, + }); -// using (var uow = DbHandler.UnitOfWork()) -// { -// var users = uow._context.Set(); -// var usr = users.FirstOrDefault(x => x.UserId == userId); + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", amount, uow).ConfigureAwait(false); -// if (usr == null) -// { -// users.Add(new RewardedUser() -// { -// UserId = userId, -// LastReward = DateTime.UtcNow, -// AmountRewardedThisMonth = amount, -// }); -// await uow.CompleteAsync().ConfigureAwait(false); -// return amount; -// } + await uow.CompleteAsync().ConfigureAwait(false); + return amount; + } -// if (usr.AmountRewardedThisMonth < amount) -// { -// var toAward = amount - usr.AmountRewardedThisMonth; + if (usr.AmountRewardedThisMonth < amount) + { + var toAward = amount - usr.AmountRewardedThisMonth; -// usr.LastReward = DateTime.UtcNow; -// usr.AmountRewardedThisMonth = amount; + usr.LastReward = DateTime.UtcNow; + usr.AmountRewardedThisMonth = amount; -// await uow.CompleteAsync().ConfigureAwait(false); -// return toAward; -// } -// } -// return 0; -// } -// finally -// { -// claimLockJustInCase.Release(); -// } -// } -// } -// } -//} + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", toAward, uow).ConfigureAwait(false); + + await uow.CompleteAsync().ConfigureAwait(false); + return toAward; + } + } + return 0; + } + finally + { + claimLockJustInCase.Release(); + } + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Resources/CommandStrings.Designer.cs b/src/NadekoBot/Resources/CommandStrings.Designer.cs index ef7c365a..76dac5be 100644 --- a/src/NadekoBot/Resources/CommandStrings.Designer.cs +++ b/src/NadekoBot/Resources/CommandStrings.Designer.cs @@ -1707,7 +1707,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to claimpatreonrewards. + /// Looks up a localized string similar to clparew. /// public static string claimpatreonrewards_cmd { get { @@ -1716,7 +1716,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. + /// Looks up a localized string similar to Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key.. /// public static string claimpatreonrewards_desc { get { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 64236de1..f3662ef3 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3322,10 +3322,10 @@ `{0}warnpunish 5 Ban` or `{0}warnpunish 3` - claimpatreonrewards + clparew - If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. + Claim patreon rewards. If you're subscribed to bot owner's patreon you can user this command to claim your rewards - assuming bot owner did setup has their patreon key. `{0}claimpatreonrewards` diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 5befa0b0..48394268 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6028,81 +6028,81 @@ namespace NadekoBot.Resources { /// /// Looks up a localized string similar to Failed claiming rewards due to one of the following reasons:. /// - public static string utility_claimpatreon_fail { + public static string utility_clpa_fail { get { - return ResourceManager.GetString("utility_claimpatreon_fail", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail", resourceCulture); } } /// /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. /// - public static string utility_claimpatreon_fail_already { + public static string utility_clpa_fail_already { get { - return ResourceManager.GetString("utility_claimpatreon_fail_already", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_already", resourceCulture); } } /// /// Looks up a localized string similar to Already rewarded. /// - public static string utility_claimpatreon_fail_already_title { + public static string utility_clpa_fail_already_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_already_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_already_title", resourceCulture); } } /// /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. /// - public static string utility_claimpatreon_fail_sup { + public static string utility_clpa_fail_sup { get { - return ResourceManager.GetString("utility_claimpatreon_fail_sup", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_sup", resourceCulture); } } /// /// Looks up a localized string similar to Not supporting. /// - public static string utility_claimpatreon_fail_sup_title { + public static string utility_clpa_fail_sup_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_sup_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_sup_title", resourceCulture); } } /// /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. /// - public static string utility_claimpatreon_fail_wait { + public static string utility_clpa_fail_wait { get { - return ResourceManager.GetString("utility_claimpatreon_fail_wait", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_wait", resourceCulture); } } /// /// Looks up a localized string similar to Wait some time. /// - public static string utility_claimpatreon_fail_wait_title { + public static string utility_clpa_fail_wait_title { get { - return ResourceManager.GetString("utility_claimpatreon_fail_wait_title", resourceCulture); + return ResourceManager.GetString("utility_clpa_fail_wait_title", resourceCulture); } } /// /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. /// - public static string utility_claimpatreon_success { + public static string utility_clpa_success { get { - return ResourceManager.GetString("utility_claimpatreon_success", resourceCulture); + return ResourceManager.GetString("utility_clpa_success", resourceCulture); } } /// /// Looks up a localized string similar to Rewards can be claimed on or after 5th of each month.. /// - public static string utility_claimpatreon_too_early { + public static string utility_clpa_too_early { get { - return ResourceManager.GetString("utility_claimpatreon_too_early", resourceCulture); + return ResourceManager.GetString("utility_clpa_too_early", resourceCulture); } } diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 0a523218..105efa2b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2369,31 +2369,31 @@ Owner ID: {2} Slowmode will no longer ignore user {0} - + Failed claiming rewards due to one of the following reasons: - + Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. - + Already rewarded - + In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. - + Not supporting - + You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. - + Wait some time - + You've received {0}. Thanks for supporting the project! - + Rewards can be claimed on or after 5th of each month. \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs index e71843b1..535f1354 100644 --- a/src/NadekoBot/Services/Database/Models/RewardedUser.cs +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -1,11 +1,11 @@ -//using System; +using System; -//namespace NadekoBot.Services.Database.Models -//{ -// public class RewardedUser -// { -// public ulong UserId { get; set; } -// public int AmountRewardedThisMonth { get; set; } -// public DateTime LastReward { get; set; } -// } -//} +namespace NadekoBot.Services.Database.Models +{ + public class RewardedUser + { + public ulong UserId { get; set; } + public int AmountRewardedThisMonth { get; set; } + public DateTime LastReward { get; set; } + } +} From 3cec4f14d0ecb035e7e60b8825d9280d8b440016 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:01:02 +0200 Subject: [PATCH 21/26] .clparew finished --- ...20170401205753_patreon-rewards.Designer.cs | 1456 +++++++++++++++++ .../20170401205753_patreon-rewards.cs | 40 + .../NadekoSqliteContextModelSnapshot.cs | 21 + .../Utility/Commands/PatreonCommands.cs | 41 +- .../Resources/ResponseStrings.Designer.cs | 24 +- src/NadekoBot/Resources/ResponseStrings.resx | 12 +- .../Database/Models/PatreonRewards.cs | 15 - .../Services/Database/Models/RewardedUser.cs | 2 +- .../Services/Database/NadekoContext.cs | 7 + 9 files changed, 1583 insertions(+), 35 deletions(-) create mode 100644 src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs create mode 100644 src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs delete mode 100644 src/NadekoBot/Services/Database/Models/PatreonRewards.cs diff --git a/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs new file mode 100644 index 00000000..e693300d --- /dev/null +++ b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs @@ -0,0 +1,1456 @@ +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using NadekoBot.Services.Database; +using NadekoBot.Services.Database.Models; +using NadekoBot.Modules.Music.Classes; + +namespace NadekoBot.Migrations +{ + [DbContext(typeof(NadekoContext))] + [Migration("20170401205753_patreon-rewards")] + partial class patreonrewards + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { + modelBuilder + .HasAnnotation("ProductVersion", "1.1.0-rtm-22752"); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.Property("UserThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiRaidSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AntiSpamSettingId"); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.HasKey("Id"); + + b.HasIndex("AntiSpamSettingId"); + + b.ToTable("AntiSpamIgnore"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Action"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("MessageThreshold"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId") + .IsUnique(); + + b.ToTable("AntiSpamSetting"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ItemId"); + + b.Property("Type"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("BlacklistItem"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BetflipMultiplier"); + + b.Property("Betroll100Multiplier"); + + b.Property("Betroll67Multiplier"); + + b.Property("Betroll91Multiplier"); + + b.Property("BufferSize"); + + b.Property("CurrencyDropAmount"); + + b.Property("CurrencyGenerationChance"); + + b.Property("CurrencyGenerationCooldown"); + + b.Property("CurrencyName"); + + b.Property("CurrencyPluralName"); + + b.Property("CurrencySign"); + + b.Property("DMHelpString"); + + b.Property("DateAdded"); + + b.Property("ErrorColor"); + + b.Property("ForwardMessages"); + + b.Property("ForwardToAllOwners"); + + b.Property("HelpString"); + + b.Property("Locale"); + + b.Property("MigrationVersion"); + + b.Property("MinimumBetAmount"); + + b.Property("OkColor"); + + b.Property("RemindMessageFormat"); + + b.Property("RotatingStatuses"); + + b.Property("TriviaCurrencyReward"); + + b.HasKey("Id"); + + b.ToTable("BotConfig"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BaseDestroyed"); + + b.Property("CallUser"); + + b.Property("ClashWarId"); + + b.Property("DateAdded"); + + b.Property("SequenceNumber"); + + b.Property("Stars"); + + b.Property("TimeAdded"); + + b.HasKey("Id"); + + b.HasIndex("ClashWarId"); + + b.ToTable("ClashCallers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("EnemyClan"); + + b.Property("GuildId"); + + b.Property("Size"); + + b.Property("StartedAt"); + + b.Property("WarState"); + + b.HasKey("Id"); + + b.ToTable("ClashOfClans"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Mapping"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandAlias"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Seconds"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("CommandCooldown"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("CommandName"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.HasIndex("Price") + .IsUnique(); + + b.ToTable("CommandPrice"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ConvertUnit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("InternalTrigger"); + + b.Property("Modifier"); + + b.Property("UnitType"); + + b.HasKey("Id"); + + b.ToTable("ConversionUnits"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Currency", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Currency"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CurrencyTransaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("CurrencyTransactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CustomReaction", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoDeleteTrigger"); + + b.Property("DateAdded"); + + b.Property("DmResponse"); + + b.Property("GuildId"); + + b.Property("IsRegex"); + + b.Property("OwnerOnly"); + + b.Property("Response"); + + b.Property("Trigger"); + + b.HasKey("Id"); + + b.ToTable("CustomReactions"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.DiscordUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AvatarId"); + + b.Property("DateAdded"); + + b.Property("Discriminator"); + + b.Property("UserId"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasAlternateKey("UserId"); + + b.ToTable("DiscordUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Amount"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("Donators"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Text"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("EightBallResponses"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildConfigId1"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.HasIndex("GuildConfigId1"); + + b.ToTable("FilterChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Word"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FilteredWord"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Type"); + + b.Property("Username"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("FollowedStream"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GCChannelId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AutoAssignRoleId"); + + b.Property("AutoDeleteByeMessages"); + + b.Property("AutoDeleteByeMessagesTimer"); + + b.Property("AutoDeleteGreetMessages"); + + b.Property("AutoDeleteGreetMessagesTimer"); + + b.Property("AutoDeleteSelfAssignedRoleMessages"); + + b.Property("ByeMessageChannelId"); + + b.Property("ChannelByeMessageText"); + + b.Property("ChannelGreetMessageText"); + + b.Property("CleverbotEnabled"); + + b.Property("DateAdded"); + + b.Property("DefaultMusicVolume"); + + b.Property("DeleteMessageOnCommand"); + + b.Property("DmGreetMessageText"); + + b.Property("ExclusiveSelfAssignedRoles"); + + b.Property("FilterInvites"); + + b.Property("FilterWords"); + + b.Property("GreetMessageChannelId"); + + b.Property("GuildId"); + + b.Property("Locale"); + + b.Property("LogSettingId"); + + b.Property("MuteRoleName"); + + b.Property("PermissionRole"); + + b.Property("RootPermissionId"); + + b.Property("SendChannelByeMessage"); + + b.Property("SendChannelGreetMessage"); + + b.Property("SendDmGreetMessage"); + + b.Property("TimeZoneId"); + + b.Property("VerbosePermissions"); + + b.Property("VoicePlusTextEnabled"); + + b.Property("WarningsInitialized"); + + b.HasKey("Id"); + + b.HasIndex("GuildId") + .IsUnique(); + + b.HasIndex("LogSettingId"); + + b.HasIndex("RootPermissionId"); + + b.ToTable("GuildConfigs"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("GuildId"); + + b.Property("Interval"); + + b.Property("Message"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("GuildRepeater"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredLogChannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("LogSettingId"); + + b.HasKey("Id"); + + b.HasIndex("LogSettingId"); + + b.ToTable("IgnoredVoicePresenceCHannels"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.LogSetting", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelCreated"); + + b.Property("ChannelCreatedId"); + + b.Property("ChannelDestroyed"); + + b.Property("ChannelDestroyedId"); + + b.Property("ChannelId"); + + b.Property("ChannelUpdated"); + + b.Property("ChannelUpdatedId"); + + b.Property("DateAdded"); + + b.Property("IsLogging"); + + b.Property("LogOtherId"); + + b.Property("LogUserPresence"); + + b.Property("LogUserPresenceId"); + + b.Property("LogVoicePresence"); + + b.Property("LogVoicePresenceId"); + + b.Property("LogVoicePresenceTTSId"); + + b.Property("MessageDeleted"); + + b.Property("MessageDeletedId"); + + b.Property("MessageUpdated"); + + b.Property("MessageUpdatedId"); + + b.Property("UserBanned"); + + b.Property("UserBannedId"); + + b.Property("UserJoined"); + + b.Property("UserJoinedId"); + + b.Property("UserLeft"); + + b.Property("UserLeftId"); + + b.Property("UserMutedId"); + + b.Property("UserPresenceChannelId"); + + b.Property("UserUnbanned"); + + b.Property("UserUnbannedId"); + + b.Property("UserUpdated"); + + b.Property("UserUpdatedId"); + + b.Property("VoicePresenceChannelId"); + + b.HasKey("Id"); + + b.ToTable("LogSettings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("ModuleName"); + + b.Property("Prefix"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("ModulePrefixes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MusicPlaylist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Author"); + + b.Property("AuthorId"); + + b.Property("DateAdded"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.ToTable("MusicPlaylists"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("MutedUserId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NextId"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("NextId") + .IsUnique(); + + b.ToTable("Permission"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Index"); + + b.Property("PrimaryTarget"); + + b.Property("PrimaryTargetId"); + + b.Property("SecondaryTarget"); + + b.Property("SecondaryTargetName"); + + b.Property("State"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("Permissionv2"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Status"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("PlayingStatus"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("MusicPlaylistId"); + + b.Property("Provider"); + + b.Property("ProviderType"); + + b.Property("Query"); + + b.Property("Title"); + + b.Property("Uri"); + + b.HasKey("Id"); + + b.HasIndex("MusicPlaylistId"); + + b.ToTable("PlaylistSong"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Quote", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AuthorId"); + + b.Property("AuthorName") + .IsRequired(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("Keyword") + .IsRequired(); + + b.Property("Text") + .IsRequired(); + + b.HasKey("Id"); + + b.ToTable("Quotes"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("DateAdded"); + + b.Property("Icon"); + + b.Property("Name"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("RaceAnimals"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Reminder", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("ChannelId"); + + b.Property("DateAdded"); + + b.Property("IsPrivate"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("UserId"); + + b.Property("When"); + + b.HasKey("Id"); + + b.ToTable("Reminders"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildId", "RoleId") + .IsUnique(); + + b.ToTable("SelfAssignableRoles"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredRole"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("SlowmodeIgnoredUser"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("BotConfigId"); + + b.Property("ChannelId"); + + b.Property("ChannelName"); + + b.Property("CommandText"); + + b.Property("DateAdded"); + + b.Property("GuildId"); + + b.Property("GuildName"); + + b.Property("Index"); + + b.Property("VoiceChannelId"); + + b.Property("VoiceChannelName"); + + b.HasKey("Id"); + + b.HasIndex("BotConfigId"); + + b.ToTable("StartupCommand"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("UnmuteAt"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("UnmuteTimer"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("UserId"); + + b.Property("type"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("PokeGame"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("RoleId"); + + b.Property("VoiceChannelId"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("VcRoleInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AffinityId"); + + b.Property("ClaimerId"); + + b.Property("DateAdded"); + + b.Property("Price"); + + b.Property("WaifuId"); + + b.HasKey("Id"); + + b.HasIndex("AffinityId"); + + b.HasIndex("ClaimerId"); + + b.HasIndex("WaifuId") + .IsUnique(); + + b.ToTable("WaifuInfo"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("NewId"); + + b.Property("OldId"); + + b.Property("UpdateType"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("NewId"); + + b.HasIndex("OldId"); + + b.HasIndex("UserId"); + + b.ToTable("WaifuUpdates"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("Forgiven"); + + b.Property("ForgivenBy"); + + b.Property("GuildId"); + + b.Property("Moderator"); + + b.Property("Reason"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.ToTable("Warnings"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("Count"); + + b.Property("DateAdded"); + + b.Property("GuildConfigId"); + + b.Property("Punishment"); + + b.Property("Time"); + + b.HasKey("Id"); + + b.HasIndex("GuildConfigId"); + + b.ToTable("WarningPunishment"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiRaidSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiRaidSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamIgnore", b => + { + b.HasOne("NadekoBot.Services.Database.Models.AntiSpamSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("AntiSpamSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiSpamSetting", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig") + .WithOne("AntiSpamSetting") + .HasForeignKey("NadekoBot.Services.Database.Models.AntiSpamSetting", "GuildConfigId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.BlacklistItem", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("Blacklist") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b => + { + b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar") + .WithMany("Bases") + .HasForeignKey("ClashWarId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandAliases") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("CommandCooldowns") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandPrice", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("CommandPrices") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.EightBallResponse", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("EightBallResponses") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilterChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterInvitesChannelIds") + .HasForeignKey("GuildConfigId"); + + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilterWordsChannelIds") + .HasForeignKey("GuildConfigId1"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FilteredWord", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FilteredWords") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.FollowedStream", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("FollowedStreams") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GCChannelId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GenerateCurrencyChannelIds") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildConfig", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany() + .HasForeignKey("LogSettingId"); + + b.HasOne("NadekoBot.Services.Database.Models.Permission", "RootPermission") + .WithMany() + .HasForeignKey("RootPermissionId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.GuildRepeater", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("GuildRepeaters") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredLogChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredChannels") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.IgnoredVoicePresenceChannel", b => + { + b.HasOne("NadekoBot.Services.Database.Models.LogSetting", "LogSetting") + .WithMany("IgnoredVoicePresenceChannelIds") + .HasForeignKey("LogSettingId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.ModulePrefix", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("ModulePrefixes") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.MutedUserId", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("MutedUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permission", b => + { + b.HasOne("NadekoBot.Services.Database.Models.Permission", "Next") + .WithOne("Previous") + .HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("Permissions") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RotatingStatusMessages") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.PlaylistSong", b => + { + b.HasOne("NadekoBot.Services.Database.Models.MusicPlaylist") + .WithMany("Songs") + .HasForeignKey("MusicPlaylistId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.RaceAnimal", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("RaceAnimals") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredRoles") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("SlowmodeIgnoredUsers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b => + { + b.HasOne("NadekoBot.Services.Database.Models.BotConfig") + .WithMany("StartupCommands") + .HasForeignKey("BotConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("UnmuteTimers") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("VcRoleInfos") + .HasForeignKey("GuildConfigId"); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity") + .WithMany() + .HasForeignKey("AffinityId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Claimer") + .WithMany() + .HasForeignKey("ClaimerId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Waifu") + .WithOne() + .HasForeignKey("NadekoBot.Services.Database.Models.WaifuInfo", "WaifuId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuUpdate", b => + { + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "New") + .WithMany() + .HasForeignKey("NewId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Old") + .WithMany() + .HasForeignKey("OldId"); + + b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b => + { + b.HasOne("NadekoBot.Services.Database.Models.GuildConfig") + .WithMany("WarnPunishments") + .HasForeignKey("GuildConfigId"); + }); + } + } +} diff --git a/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs new file mode 100644 index 00000000..83057ff5 --- /dev/null +++ b/src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace NadekoBot.Migrations +{ + public partial class patreonrewards : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "RewardedUsers", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + AmountRewardedThisMonth = table.Column(nullable: false), + DateAdded = table.Column(nullable: true), + LastReward = table.Column(nullable: false), + UserId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RewardedUsers", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_RewardedUsers_UserId", + table: "RewardedUsers", + column: "UserId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RewardedUsers"); + } + } +} diff --git a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs index 3f6df376..303783e4 100644 --- a/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs +++ b/src/NadekoBot/Migrations/NadekoSqliteContextModelSnapshot.cs @@ -931,6 +931,27 @@ namespace NadekoBot.Migrations b.ToTable("Reminders"); }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd(); + + b.Property("AmountRewardedThisMonth"); + + b.Property("DateAdded"); + + b.Property("LastReward"); + + b.Property("UserId"); + + b.HasKey("Id"); + + b.HasIndex("UserId") + .IsUnique(); + + b.ToTable("RewardedUsers"); + }); + modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b => { b.Property("Id") diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 6415dd8f..e9b78014 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -12,6 +12,7 @@ using System.Collections.Immutable; using NadekoBot.Services; using NadekoBot.Services.Database.Models; using NadekoBot.Extensions; +using Discord; namespace NadekoBot.Modules.Utility { @@ -31,10 +32,11 @@ namespace NadekoBot.Modules.Utility { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; - if (DateTime.UtcNow.Day < 5) - { - await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); - } + //if (DateTime.UtcNow.Day < 5) + //{ + // await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + // return; + //} int amount = 0; try { @@ -50,12 +52,13 @@ namespace NadekoBot.Modules.Utility await ReplyConfirmLocalized("clpa_success", amount + NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false); return; } - - await Context.Channel.EmbedAsync(new Discord.EmbedBuilder().WithOkColor() + var helpcmd = Format.Code(NadekoBot.ModulePrefixes[typeof(Help.Help).Name] + "donate"); + await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor() .WithDescription(GetText("clpa_fail")) .AddField(efb => efb.WithName(GetText("clpa_fail_already_title")).WithValue(GetText("clpa_fail_already"))) .AddField(efb => efb.WithName(GetText("clpa_fail_wait_title")).WithValue(GetText("clpa_fail_wait"))) - .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup")))) + .AddField(efb => efb.WithName(GetText("clpa_fail_conn_title")).WithValue(GetText("clpa_fail_conn"))) + .AddField(efb => efb.WithName(GetText("clpa_fail_sup_title")).WithValue(GetText("clpa_fail_sup", helpcmd)))) .ConfigureAwait(false); } } @@ -129,9 +132,10 @@ namespace NadekoBot.Modules.Utility public async Task ClaimReward(ulong userId) { await claimLockJustInCase.WaitAsync(); + var now = DateTime.UtcNow; try { - var data = Pledges.FirstOrDefault(x => x.User.id == userId.ToString()); + var data = Pledges.FirstOrDefault(x => x.User.attributes?.social_connections?.discord?.user_id == userId.ToString()); if (data == null) return 0; @@ -148,24 +152,35 @@ namespace NadekoBot.Modules.Utility users.Add(new RewardedUser() { UserId = userId, - LastReward = DateTime.UtcNow, + LastReward = now, AmountRewardedThisMonth = amount, }); - await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", amount, uow).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - new", amount, uow).ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false); return amount; } - if (usr.AmountRewardedThisMonth < amount) + if (usr.LastReward.Month != now.Month) + { + usr.LastReward = now; + usr.AmountRewardedThisMonth = amount; + + await CurrencyHandler.AddCurrencyAsync(userId, "Patreon reward - recurring", amount, uow).ConfigureAwait(false); + + await uow.CompleteAsync().ConfigureAwait(false); + return amount; + } + + if ( usr.AmountRewardedThisMonth < amount) { var toAward = amount - usr.AmountRewardedThisMonth; - usr.LastReward = DateTime.UtcNow; + usr.LastReward = now; usr.AmountRewardedThisMonth = amount; - await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward", toAward, uow).ConfigureAwait(false); + await CurrencyHandler.AddCurrencyAsync(usr.UserId, "Patreon reward - update", toAward, uow).ConfigureAwait(false); await uow.CompleteAsync().ConfigureAwait(false); return toAward; diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 48394268..445e025b 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -6035,7 +6035,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. + /// Looks up a localized string similar to Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge.. /// public static string utility_clpa_fail_already { get { @@ -6053,7 +6053,25 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link.. + /// Looks up a localized string similar to Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button.. + /// + public static string utility_clpa_fail_conn { + get { + return ResourceManager.GetString("utility_clpa_fail_conn", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Discord account not connected. + /// + public static string utility_clpa_fail_conn_title { + get { + return ResourceManager.GetString("utility_clpa_fail_conn_title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link.. /// public static string utility_clpa_fail_sup { get { @@ -6071,7 +6089,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later.. + /// Looks up a localized string similar to You have to wait a few hours after making your pledge, if you didn't, try again later.. /// public static string utility_clpa_fail_wait { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 105efa2b..4d605da8 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2373,19 +2373,25 @@ Owner ID: {2} Failed claiming rewards due to one of the following reasons: - Maybe you have already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. Already rewarded + + Your discord account might not be connected to Patreon.. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. + + + Discord account not connected + - In order to be eligible for the reward, you must support the project on patreon. Use {0} command to get the link. + In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link. Not supporting - You have to wait a few hours after making your pledge, if you didn't, waiut a bit and then try again later. + You have to wait a few hours after making your pledge, if you didn't, try again later. Wait some time diff --git a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs b/src/NadekoBot/Services/Database/Models/PatreonRewards.cs deleted file mode 100644 index 0e1532b3..00000000 --- a/src/NadekoBot/Services/Database/Models/PatreonRewards.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace NadekoBot.Services.Database.Models -{ - public class PatreonRewards : DbEntity - { - public ulong UserId { get; set; } - public ulong PledgeCents { get; set; } - public ulong Awarded { get; set; } - } -} diff --git a/src/NadekoBot/Services/Database/Models/RewardedUser.cs b/src/NadekoBot/Services/Database/Models/RewardedUser.cs index 535f1354..f7db8dc4 100644 --- a/src/NadekoBot/Services/Database/Models/RewardedUser.cs +++ b/src/NadekoBot/Services/Database/Models/RewardedUser.cs @@ -2,7 +2,7 @@ namespace NadekoBot.Services.Database.Models { - public class RewardedUser + public class RewardedUser : DbEntity { public ulong UserId { get; set; } public int AmountRewardedThisMonth { get; set; } diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index a82cfde8..9c084867 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -51,6 +51,7 @@ namespace NadekoBot.Services.Database public DbSet EightBallResponses { get; set; } public DbSet RaceAnimals { get; set; } public DbSet ModulePrefixes { get; set; } + public DbSet RewardedUsers { get; set; } public NadekoContext() : base() { @@ -277,6 +278,12 @@ namespace NadekoBot.Services.Database #region Warnings var warn = modelBuilder.Entity(); #endregion + + #region PatreonRewards + var pr = modelBuilder.Entity(); + pr.HasIndex(x => x.UserId) + .IsUnique(); + #endregion } } } From c512f6360b0fe32d312fde5f28b89addfae5ea7b Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:25:26 +0200 Subject: [PATCH 22/26] .slowmodewl implemented and now works properly --- .../Commands/RatelimitCommand.cs | 45 ++++++++++--------- .../Resources/ResponseStrings.Designer.cs | 10 ++--- src/NadekoBot/Resources/ResponseStrings.resx | 10 ++--- .../Impl/GuildConfigRepository.cs | 2 + 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs index 0c0f91be..57dd4c89 100644 --- a/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs @@ -5,7 +5,6 @@ using Microsoft.EntityFrameworkCore; using NadekoBot.Attributes; using NadekoBot.Extensions; using NadekoBot.Services; -using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; @@ -20,16 +19,16 @@ namespace NadekoBot.Modules.Administration public partial class Administration { [Group] - public class RatelimitCommand : NadekoSubmodule + public class RatelimitCommands : NadekoSubmodule { public static ConcurrentDictionary RatelimitingChannels = new ConcurrentDictionary(); + public static ConcurrentDictionary> IgnoredRoles = new ConcurrentDictionary>(); + public static ConcurrentDictionary> IgnoredUsers = new ConcurrentDictionary>(); + private new static readonly Logger _log; public class Ratelimiter { - public HashSet IgnoreUsers { get; set; } = new HashSet(); - public HashSet IgnoreRoles { get; set; } = new HashSet(); - public class RatelimitedUser { public ulong UserId { get; set; } @@ -45,10 +44,13 @@ namespace NadekoBot.Modules.Administration public ConcurrentDictionary Users { get; set; } = new ConcurrentDictionary(); - public bool CheckUserRatelimit(ulong id, SocketGuildUser optUser) + public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser) { - if (IgnoreUsers.Contains(id) || - (optUser != null && optUser.RoleIds.Any(x => IgnoreRoles.Contains(x)))) + HashSet ignoreUsers; + HashSet ignoreRoles; + + if ((IgnoredUsers.TryGetValue(guildId, out ignoreUsers) && ignoreUsers.Contains(id)) || + (optUser != null && IgnoredRoles.TryGetValue(guildId, out ignoreRoles) && optUser.RoleIds.Any(x => ignoreRoles.Contains(x)))) return false; var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id }); @@ -70,10 +72,20 @@ namespace NadekoBot.Modules.Administration } } - static RatelimitCommand() + static RatelimitCommands() { _log = LogManager.GetCurrentClassLogger(); + IgnoredRoles = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs + .ToDictionary(x => x.GuildId, + x => new HashSet(x.SlowmodeIgnoredRoles.Select(y => y.RoleId)))); + + IgnoredUsers = new ConcurrentDictionary>( + NadekoBot.AllGuildConfigs + .ToDictionary(x => x.GuildId, + x => new HashSet(x.SlowmodeIgnoredUsers.Select(y => y.UserId)))); + NadekoBot.Client.MessageReceived += async (umsg) => { try @@ -87,7 +99,7 @@ namespace NadekoBot.Modules.Administration if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter)) return; - if (limiter.CheckUserRatelimit(usrMsg.Author.Id, usrMsg.Author as SocketGuildUser)) + if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser)) await usrMsg.DeleteAsync(); } catch (Exception ex) { _log.Warn(ex); } @@ -157,11 +169,8 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - Ratelimiter rl; - if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) - { - rl.IgnoreUsers = new HashSet(usrs.Select(x => x.UserId)); - } + IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet(usrs.Select(x => x.UserId)), (key, old) => new HashSet(usrs.Select(x => x.UserId))); + if(removed) await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false); else @@ -192,11 +201,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync().ConfigureAwait(false); } - Ratelimiter rl; - if (RatelimitingChannels.TryGetValue(Context.Guild.Id, out rl)) - { - rl.IgnoreRoles = new HashSet(roles.Select(x => x.RoleId)); - } + IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet(roles.Select(x => x.RoleId)), (key, old) => new HashSet(roles.Select(x => x.RoleId))); if (removed) await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false); diff --git a/src/NadekoBot/Resources/ResponseStrings.Designer.cs b/src/NadekoBot/Resources/ResponseStrings.Designer.cs index 445e025b..e13d8513 100644 --- a/src/NadekoBot/Resources/ResponseStrings.Designer.cs +++ b/src/NadekoBot/Resources/ResponseStrings.Designer.cs @@ -1513,7 +1513,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will now ignore role {0}. + /// Looks up a localized string similar to Slowmode will now ignore {0} role.. /// public static string administration_slowmodewl_role_start { get { @@ -1522,7 +1522,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will no longer ignore role {0}. + /// Looks up a localized string similar to Slowmode will no longer ignore {0} role.. /// public static string administration_slowmodewl_role_stop { get { @@ -1531,7 +1531,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will now ignore user {0}. + /// Looks up a localized string similar to Slowmode will now ignore user {0}.. /// public static string administration_slowmodewl_user_start { get { @@ -1540,7 +1540,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to Slowmode will no longer ignore user {0}. + /// Looks up a localized string similar to Slowmode will no longer ignore user {0}.. /// public static string administration_slowmodewl_user_stop { get { @@ -6107,7 +6107,7 @@ namespace NadekoBot.Resources { } /// - /// Looks up a localized string similar to You've received {0}. Thanks for supporting the project!. + /// Looks up a localized string similar to You've received {0} Thanks for supporting the project!. /// public static string utility_clpa_success { get { diff --git a/src/NadekoBot/Resources/ResponseStrings.resx b/src/NadekoBot/Resources/ResponseStrings.resx index 4d605da8..83d701f3 100644 --- a/src/NadekoBot/Resources/ResponseStrings.resx +++ b/src/NadekoBot/Resources/ResponseStrings.resx @@ -2358,16 +2358,16 @@ Owner ID: {2} I will apply {0} punishment to users with {1} warnings. - Slowmode will now ignore role {0} + Slowmode will now ignore {0} role. - Slowmode will no longer ignore role {0} + Slowmode will no longer ignore {0} role. - Slowmode will now ignore user {0} + Slowmode will now ignore user {0}. - Slowmode will no longer ignore user {0} + Slowmode will no longer ignore user {0}. Failed claiming rewards due to one of the following reasons: @@ -2397,7 +2397,7 @@ Owner ID: {2} Wait some time - You've received {0}. Thanks for supporting the project! + You've received {0} Thanks for supporting the project! Rewards can be claimed on or after 5th of each month. diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 01a44677..ebe41406 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -38,6 +38,8 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.CommandCooldowns) .Include(gc => gc.GuildRepeaters) .Include(gc => gc.AntiRaidSetting) + .Include(gc => gc.SlowmodeIgnoredRoles) + .Include(gc => gc.SlowmodeIgnoredUsers) .Include(gc => gc.AntiSpamSetting) .ThenInclude(x => x.IgnoredChannels) .ToList(); From 3364f110a47f3e78b7d77c13a690ba45c4f9a5e9 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 00:26:44 +0200 Subject: [PATCH 23/26] Startup commands will now run with 400ms delay between each other --- src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 09924682..dcb36766 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -57,6 +57,7 @@ namespace NadekoBot.Modules.Administration } catch { } } + await Task.Delay(400).ConfigureAwait(false); } }); } From dfdfab44f7e28069944470c898544f3847c6813d Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 02:33:43 +0200 Subject: [PATCH 24/26] Woops, forgot to uncomment day check --- .../Modules/Utility/Commands/PatreonCommands.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index e9b78014..303774f4 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -32,11 +32,11 @@ namespace NadekoBot.Modules.Utility { if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.PatreonAccessToken)) return; - //if (DateTime.UtcNow.Day < 5) - //{ - // await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); - // return; - //} + if (DateTime.UtcNow.Day < 5) + { + await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); + return; + } int amount = 0; try { From e3a1d17d8e863eaa2fae1b9eac7a0984a37ba17a Mon Sep 17 00:00:00 2001 From: Kwoth Date: Sun, 2 Apr 2017 12:45:35 +0200 Subject: [PATCH 25/26] $lb can't take negative page numbers anymore xD --- src/NadekoBot/Modules/Gambling/Gambling.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/NadekoBot/Modules/Gambling/Gambling.cs b/src/NadekoBot/Modules/Gambling/Gambling.cs index 760f8156..83db6048 100644 --- a/src/NadekoBot/Modules/Gambling/Gambling.cs +++ b/src/NadekoBot/Modules/Gambling/Gambling.cs @@ -246,6 +246,9 @@ namespace NadekoBot.Modules.Gambling [NadekoCommand, Usage, Description, Aliases] public async Task Leaderboard(int page = 1) { + if (page < 1) + return; + List richest; using (var uow = DbHandler.UnitOfWork()) { From 9afab5ad4c7afcb954b54bd30b9ae62f5bc4bb12 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 2 Apr 2017 18:26:27 +0200 Subject: [PATCH 26/26] Update ResponseStrings.en-US.resx (POEditor.com) --- .../Resources/ResponseStrings.en-US.resx | 126 +++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Resources/ResponseStrings.en-US.resx b/src/NadekoBot/Resources/ResponseStrings.en-US.resx index ccff686e..753f8135 100644 --- a/src/NadekoBot/Resources/ResponseStrings.en-US.resx +++ b/src/NadekoBot/Resources/ResponseStrings.en-US.resx @@ -740,7 +740,7 @@ Reason: {1} Slow mode initiated - soft-banned (kicked) + soft-banned PLURAL @@ -2278,5 +2278,129 @@ Owner ID: {2} Competitive playtime + + Channel + + + Command Text + + + Kicked + PLURAL + + + Moderator + + + page {0} + + + Reason + + + New startup command added. + + + Startup command successfully removed. + + + Startup command not found. + + + Server + + + No startup commands on this page. + + + Cleared all startup commands. + + + User {0} has been unbanned. + + + User not found. + + + User {0} has been warned. + + + User {0} has been warned and {1} punishment has been applied. + + + Warned on {0} server + + + On {0} at {1} by {2} + + + All warnings have been cleared for {0}. + + + No warning on this page. + + + Warnlog for {0} + + + No punishments set. + + + cleared by {0} + + + Warning punishment list + + + Having {0} warnings will no longer trigger a punishment. + + + I will apply {0} punishment to users with {1} warnings. + + + Slowmode will now ignore {0} role. + + + Slowmode will no longer ignore {0} role. + + + Slowmode will now ignore user {0}. + + + Slowmode will no longer ignore user {0}. + + + Failed claiming rewards due to one of the following reasons: + + + Maybe you've already received your reward for this month. You can receive rewards only once a month unless you increase your pledge. + + + Already rewarded + + + Your discord account might not be connected to Patreon. If you are unsure what that means, or don't know how to connect it - you have to go to [Patreon account settings page](https://patreon.com/settings/account) and click 'Connect to discord' button. + + + Discord account not connected + + + In order to be eligible for the reward, you must support the project on patreon. You can use {0} command to get the link. + + + Not supporting + + + You have to wait a few hours after making your pledge, if you didn't, try again later. + + + Wait some time + + + You've received {0} Thanks for supporting the project! + + + Rewards can be claimed on or after 5th of each month. + \ No newline at end of file